├── tests ├── __init__.py ├── test_snapshots │ ├── __init__.py │ ├── snapshots │ │ ├── alpha_default.json5 │ │ ├── alpha_no_indent.json5 │ │ ├── alpha_no_comments.json5 │ │ ├── alpha_no_trailing_comma.json5 │ │ ├── alpha_special_separators.json5 │ │ ├── alpha_with_trailing_comma.json5 │ │ ├── alpha_7_indent.json5 │ │ └── alpha_with_comments.json5 │ └── generate_snapshots.py ├── json5_examples │ ├── misc │ │ ├── empty.txt │ │ ├── valid-whitespace.json5 │ │ ├── readme-example.json5 │ │ ├── npm-package.json5 │ │ └── npm-package.json │ ├── arrays │ │ ├── empty-array.json │ │ ├── leading-comma-array.js │ │ ├── lone-trailing-comma-array.js │ │ ├── trailing-comma-array.json5 │ │ ├── no-comma-array.txt │ │ ├── regular-array.json │ │ └── no-comma-array.errorSpec │ ├── numbers │ │ ├── float.json │ │ ├── integer.json │ │ ├── nan.json5 │ │ ├── noctal.js │ │ ├── octal.txt │ │ ├── zero-float.json │ │ ├── zero-integer.json │ │ ├── zero-octal.txt │ │ ├── hexadecimal-empty.txt │ │ ├── hexadecimal.json5 │ │ ├── infinity.json5 │ │ ├── lone-decimal-point.txt │ │ ├── negative-float.json │ │ ├── negative-integer.json │ │ ├── negative-noctal.js │ │ ├── negative-octal.txt │ │ ├── positive-float.json5 │ │ ├── positive-noctal.js │ │ ├── positive-octal.txt │ │ ├── float-leading-zero.json │ │ ├── negative-zero-float.json │ │ ├── negative-zero-integer.json │ │ ├── negative-zero-octal.txt │ │ ├── positive-integer.json5 │ │ ├── positive-zero-float.json5 │ │ ├── positive-zero-integer.json5 │ │ ├── positive-zero-octal.txt │ │ ├── zero-hexadecimal.json5 │ │ ├── hexadecimal-uppercase-x.json5 │ │ ├── negative-hexadecimal.json5 │ │ ├── negative-infinity.json5 │ │ ├── positive-hexadecimal.json5 │ │ ├── positive-infinity.json5 │ │ ├── float-leading-decimal-point.json5 │ │ ├── float-trailing-decimal-point.json5 │ │ ├── float-with-integer-exponent.json │ │ ├── hexadecimal-lowercase-letter.json5 │ │ ├── integer-with-float-exponent.txt │ │ ├── integer-with-integer-exponent.json │ │ ├── negative-float-leading-zero.json │ │ ├── negative-zero-hexadecimal.json5 │ │ ├── noctal-with-leading-octal-digit.js │ │ ├── positive-float-leading-zero.json5 │ │ ├── positive-zero-hexadecimal.json5 │ │ ├── integer-with-hexadecimal-exponent.txt │ │ ├── integer-with-zero-integer-exponent.json │ │ ├── zero-float-leading-decimal-point.json5 │ │ ├── zero-float-trailing-decimal-point.json5 │ │ ├── zero-integer-with-integer-exponent.json │ │ ├── hexadecimal-with-integer-exponent.json5 │ │ ├── integer-with-negative-float-exponent.txt │ │ ├── integer-with-negative-integer-exponent.json │ │ ├── integer-with-positive-float-exponent.txt │ │ ├── integer-with-positive-integer-exponent.json │ │ ├── negative-float-leading-decimal-point.json5 │ │ ├── negative-float-trailing-decimal-point.json5 │ │ ├── positive-float-leading-decimal-point.json5 │ │ ├── positive-float-trailing-decimal-point.json5 │ │ ├── integer-with-negative-hexadecimal-exponent.txt │ │ ├── integer-with-negative-zero-integer-exponent.json │ │ ├── integer-with-positive-hexadecimal-exponent.txt │ │ ├── integer-with-positive-zero-integer-exponent.json │ │ ├── negative-zero-float-leading-decimal-point.json5 │ │ ├── negative-zero-float-trailing-decimal-point.json5 │ │ ├── positive-zero-float-leading-decimal-point.json5 │ │ ├── positive-zero-float-trailing-decimal-point.json5 │ │ └── float-trailing-decimal-point-with-integer-exponent.json5 │ ├── objects │ │ ├── empty-object.json │ │ ├── no-colon-object.txt │ │ ├── lone-trailing-comma-object.txt │ │ ├── leading-comma-object.txt │ │ ├── reserved-unquoted-key.json5 │ │ ├── single-quoted-key.json5 │ │ ├── trailing-comma-object.json5 │ │ ├── duplicate-keys.json │ │ ├── illegal-unquoted-key-number.txt │ │ ├── illegal-unquoted-key-symbol.txt │ │ ├── no-comma-object.txt │ │ ├── leading-comma-object.errorSpec │ │ ├── illegal-unquoted-key-number.errorSpec │ │ ├── illegal-unquoted-key-symbol.errorSpec │ │ └── unquoted-keys.json5 │ ├── strings │ │ ├── single-quoted-string.json5 │ │ ├── multi-line-string.json5 │ │ ├── escaped-single-quoted-string.json5 │ │ ├── unescaped-multi-line-string.txt │ │ ├── unescaped-multi-line-string.errorSpec │ │ └── no-comma-array.errorSpec │ ├── new-lines │ │ ├── comment-cr.json5 │ │ ├── comment-lf.json5 │ │ ├── comment-crlf.json5 │ │ ├── escaped-cr.json5 │ │ ├── escaped-lf.json5 │ │ ├── escaped-crlf.json5 │ │ ├── .gitattributes │ │ └── .editorconfig │ ├── comments │ │ ├── inline-comment-following-array-element.json5 │ │ ├── block-comment-in-string.json │ │ ├── inline-comment-in-string.json │ │ ├── top-level-inline-comment.txt │ │ ├── block-comment-following-array-element.json5 │ │ ├── inline-comment-following-top-level-value.json5 │ │ ├── top-level-block-comment.txt │ │ ├── inline-comment-preceding-top-level-value.json5 │ │ ├── top-level-block-comment.errorSpec │ │ ├── block-comment-following-top-level-value.json5 │ │ ├── block-comment-preceding-top-level-value.json5 │ │ ├── top-level-inline-comment.errorSpec │ │ ├── unterminated-block-comment.txt │ │ └── block-comment-with-asterisks.json5 │ ├── todo │ │ ├── unicode-escaped-unquoted-key.json5 │ │ └── unicode-unquoted-key.json5 │ ├── README.md │ └── LICENSE.md ├── json_test_suite │ ├── test_parsing │ │ ├── n_number_+1.json │ │ ├── n_number_-01.json │ │ ├── n_number_-2..json │ │ ├── n_number_.-1.json │ │ ├── n_number_0e+.json │ │ ├── n_number_0e.json │ │ ├── n_number_Inf.json │ │ ├── n_number_NaN.json │ │ ├── n_single_space.json │ │ ├── y_array_empty.json │ │ ├── y_array_null.json │ │ ├── y_number.json │ │ ├── y_number_0e1.json │ │ ├── y_object_empty.json │ │ ├── y_string_pi.json │ │ ├── y_string_space.json │ │ ├── n_array_incomplete.json │ │ ├── n_array_just_comma.json │ │ ├── n_array_just_minus.json │ │ ├── n_array_star_inside.json │ │ ├── n_array_unclosed.json │ │ ├── n_incomplete_null.json │ │ ├── n_incomplete_true.json │ │ ├── n_number_++.json │ │ ├── n_number_+Inf.json │ │ ├── n_number_-1.0..json │ │ ├── n_number_-NaN.json │ │ ├── n_number_.2e-3.json │ │ ├── n_number_0.1.2.json │ │ ├── n_number_0.3e+.json │ │ ├── n_number_0.3e.json │ │ ├── n_number_0.e1.json │ │ ├── n_number_1.0e+.json │ │ ├── n_number_1.0e-.json │ │ ├── n_number_1.0e.json │ │ ├── n_number_1_000.json │ │ ├── n_number_1eE2.json │ │ ├── n_number_2.e+3.json │ │ ├── n_number_2.e-3.json │ │ ├── n_number_2.e3.json │ │ ├── n_number_9.e+.json │ │ ├── n_object_emoji.json │ │ ├── n_object_no-colon.json │ │ ├── n_structure_end_array.json │ │ ├── n_structure_no_data.json │ │ ├── y_array_false.json │ │ ├── y_number_0e+1.json │ │ ├── y_number_minus_zero.json │ │ ├── y_object_simple.json │ │ ├── y_string_utf8.json │ │ ├── n_array_comma_and_number.json │ │ ├── n_array_double_comma.json │ │ ├── n_array_extra_close.json │ │ ├── n_array_extra_comma.json │ │ ├── n_array_number_and_comma.json │ │ ├── n_incomplete_false.json │ │ ├── n_number_0_capital_E+.json │ │ ├── n_number_0_capital_E.json │ │ ├── n_number_expression.json │ │ ├── n_number_hex_1_digit.json │ │ ├── n_number_hex_2_digits.json │ │ ├── n_number_infinity.json │ │ ├── n_number_invalid+-.json │ │ ├── n_number_minus_space_1.json │ │ ├── n_number_with_alpha.json │ │ ├── n_object_missing_key.json │ │ ├── n_object_missing_value.json │ │ ├── n_object_non_string_key.json │ │ ├── n_object_single_quote.json │ │ ├── n_string_backslash_00.json │ │ ├── n_string_escape_x.json │ │ ├── n_string_single_doublequote.json │ │ ├── n_string_unescaped_tab.json │ │ ├── n_structure_UTF8_BOM_no_data.json │ │ ├── n_structure_double_array.json │ │ ├── n_structure_open_object.json │ │ ├── n_structure_single_star.json │ │ ├── n_structure_unclosed_array.json │ │ ├── y_array_empty-string.json │ │ ├── y_number_after_space.json │ │ ├── y_number_int_with_exp.json │ │ ├── y_number_negative_int.json │ │ ├── y_number_negative_one.json │ │ ├── y_number_negative_zero.json │ │ ├── y_number_real_neg_exp.json │ │ ├── y_number_simple_int.json │ │ ├── y_object_basic.json │ │ ├── y_object_empty_key.json │ │ ├── y_string_in_array.json │ │ ├── y_string_u+2029_par_sep.json │ │ ├── y_string_unicode.json │ │ ├── y_string_unicode_2.json │ │ ├── y_structure_lonely_int.json │ │ ├── y_structure_lonely_null.json │ │ ├── y_structure_lonely_true.json │ │ ├── y_structure_string_empty.json │ │ ├── n_array_comma_after_close.json │ │ ├── n_array_double_extra_comma.json │ │ ├── n_array_missing_value.json │ │ ├── n_multidigit_number_then_00.json │ │ ├── n_number_starting_with_dot.json │ │ ├── n_number_with_leading_zero.json │ │ ├── n_object_bad_value.json │ │ ├── n_object_bracket_key.json │ │ ├── n_object_double_colon.json │ │ ├── n_object_missing_colon.json │ │ ├── n_object_trailing_comma.json │ │ ├── n_object_unquoted_key.json │ │ ├── n_string_escaped_emoji.json │ │ ├── n_string_incomplete_escape.json │ │ ├── n_string_start_escape_unclosed.json │ │ ├── n_string_unicode_CapitalU.json │ │ ├── n_string_with_trailing_garbage.json │ │ ├── n_structure_U+2060_word_joined.json │ │ ├── n_structure_angle_bracket_..json │ │ ├── n_structure_lone-open-bracket.json │ │ ├── n_structure_open_array_comma.json │ │ ├── n_structure_open_array_string.json │ │ ├── n_structure_open_object_comma.json │ │ ├── n_structure_unicode-identifier.json │ │ ├── y_array_arraysWithSpaces.json │ │ ├── y_array_ending_with_newline.json │ │ ├── y_array_with_leading_space.json │ │ ├── y_array_with_trailing_space.json │ │ ├── y_number_real_capital_e.json │ │ ├── y_number_real_exponent.json │ │ ├── y_number_real_pos_exponent.json │ │ ├── y_number_simple_real.json │ │ ├── y_string_double_escape_a.json │ │ ├── y_string_double_escape_n.json │ │ ├── y_string_null_escape.json │ │ ├── y_string_one-byte-utf-8.json │ │ ├── y_string_simple_ascii.json │ │ ├── y_string_two-byte-utf-8.json │ │ ├── y_string_u+2028_line_sep.json │ │ ├── y_structure_lonely_false.json │ │ ├── y_structure_lonely_string.json │ │ ├── y_structure_true_in_array.json │ │ ├── y_structure_whitespace_array.json │ │ ├── i_number_neg_int_huge_exp.json │ │ ├── i_number_real_underflow.json │ │ ├── i_structure_UTF-8_BOM_empty_object.json │ │ ├── n_array_1_true_without_comma.json │ │ ├── n_array_colon_instead_of_comma.json │ │ ├── n_array_incomplete_invalid_value.json │ │ ├── n_array_inner_array_no_comma.json │ │ ├── n_array_number_and_several_commas.json │ │ ├── n_array_unclosed_trailing_comma.json │ │ ├── n_array_unclosed_with_object_inside.json │ │ ├── n_number_U+FF11_fullwidth_digit_one.json │ │ ├── n_number_minus_infinity.json │ │ ├── n_number_neg_with_garbage_at_end.json │ │ ├── n_number_real_garbage_after_e.json │ │ ├── n_object_garbage_at_end.json │ │ ├── n_object_missing_semicolon.json │ │ ├── n_object_trailing_comment.json │ │ ├── n_object_unterminated-value.json │ │ ├── n_string_accentuated_char_no_quotes.json │ │ ├── n_string_escaped_backslash_bad.json │ │ ├── n_string_escaped_ctrl_char_tab.json │ │ ├── n_string_invalid_backslash_esc.json │ │ ├── n_string_no_quotes_with_bad_escape.json │ │ ├── n_string_single_quote.json │ │ ├── n_string_unescaped_ctrl_char.json │ │ ├── n_structure_angle_bracket_null.json │ │ ├── n_structure_array_trailing_garbage.json │ │ ├── n_structure_ascii-unicode-identifier.json │ │ ├── n_structure_capitalized_True.json │ │ ├── n_structure_close_unopened_array.json │ │ ├── n_structure_open_array_apostrophe.json │ │ ├── n_structure_open_array_open_object.json │ │ ├── n_structure_open_array_open_string.json │ │ ├── n_structure_open_object_close_array.json │ │ ├── n_structure_open_object_open_array.json │ │ ├── n_structure_open_object_open_string.json │ │ ├── n_structure_open_open.json │ │ ├── n_structure_trailing_#.json │ │ ├── n_structure_whitespace_formfeed.json │ │ ├── y_array_with_1_and_newline.json │ │ ├── y_number_real_capital_e_neg_exp.json │ │ ├── y_number_real_capital_e_pos_exp.json │ │ ├── y_object.json │ │ ├── y_string_backslash_doublequotes.json │ │ ├── y_string_comments.json │ │ ├── y_string_three-byte-utf-8.json │ │ ├── y_string_unescaped_char_delete.json │ │ ├── y_string_with_del_character.json │ │ ├── y_structure_lonely_negative_real.json │ │ ├── y_structure_trailing_newline.json │ │ ├── i_number_double_huge_neg_exp.json │ │ ├── i_number_pos_double_huge_exp.json │ │ ├── i_number_real_neg_overflow.json │ │ ├── i_number_real_pos_overflow.json │ │ ├── i_object_key_lone_2nd_surrogate.json │ │ ├── i_string_invalid_lonely_surrogate.json │ │ ├── i_string_invalid_surrogate.json │ │ ├── i_string_lone_second_surrogate.json │ │ ├── n_array_items_separated_by_semicolon.json │ │ ├── n_number_invalid-negative-real.json │ │ ├── n_number_neg_int_starting_with_zero.json │ │ ├── n_number_neg_real_without_int_part.json │ │ ├── n_number_real_without_fractional_part.json │ │ ├── n_object_comma_instead_of_colon.json │ │ ├── n_object_with_trailing_garbage.json │ │ ├── n_string_1_surrogate_then_escape.json │ │ ├── n_string_incomplete_surrogate.json │ │ ├── n_string_invalid_unicode_escape.json │ │ ├── n_string_single_string_no_double_quotes.json │ │ ├── n_string_unescaped_newline.json │ │ ├── n_structure_null-byte-outside-string.json │ │ ├── n_structure_number_with_trailing_garbage.json │ │ ├── n_structure_object_unclosed_no_value.json │ │ ├── n_structure_unclosed_object.json │ │ ├── y_array_heterogeneous.json │ │ ├── y_number_real_fraction_exponent.json │ │ ├── y_object_duplicated_key.json │ │ ├── y_object_with_newlines.json │ │ ├── y_string_escaped_noncharacter.json │ │ ├── y_string_nbsp_uescaped.json │ │ ├── y_string_nonCharacterInUTF-8_U+10FFFF.json │ │ ├── y_string_nonCharacterInUTF-8_U+FFFF.json │ │ ├── y_string_uescaped_newline.json │ │ ├── y_string_unicodeEscapedBackslash.json │ │ ├── y_string_unicode_U+FDD0_nonchar.json │ │ ├── y_string_unicode_U+FFFE_nonchar.json │ │ ├── i_number_too_big_pos_int.json │ │ ├── i_string_1st_surrogate_but_2nd_missing.json │ │ ├── i_string_incomplete_surrogate_pair.json │ │ ├── n_array_newlines_unclosed.json │ │ ├── n_array_spaces_vertical_tab_formfeed.json │ │ ├── n_array_unclosed_with_new_lines.json │ │ ├── n_number_minus_sign_with_trailing_garbage.json │ │ ├── n_object_key_with_single_quotes.json │ │ ├── n_object_repeated_null_null.json │ │ ├── n_object_several_trailing_commas.json │ │ ├── n_object_trailing_comment_open.json │ │ ├── n_object_trailing_comment_slash_open.json │ │ ├── n_object_two_commas_in_a_row.json │ │ ├── n_string_1_surrogate_then_escape_u.json │ │ ├── n_string_1_surrogate_then_escape_u1.json │ │ ├── n_string_incomplete_escaped_character.json │ │ ├── n_string_leading_uescaped_thinspace.json │ │ ├── n_structure_array_with_extra_array_close.json │ │ ├── n_structure_array_with_unclosed_string.json │ │ ├── n_structure_object_followed_by_closing_object.json │ │ ├── n_structure_uescaped_LF_before_string.json │ │ ├── n_structure_whitespace_U+2060_word_joiner.json │ │ ├── y_array_with_several_null.json │ │ ├── y_object_escaped_null_in_key.json │ │ ├── y_string_accepted_surrogate_pair.json │ │ ├── y_string_backslash_and_u_escaped_zero.json │ │ ├── y_string_escaped_control_character.json │ │ ├── y_string_in_array_with_leading_space.json │ │ ├── y_string_last_surrogates_1_and_2.json │ │ ├── y_string_reservedCharacterInUTF-8_U+1BFFF.json │ │ ├── y_string_uEscape.json │ │ ├── y_string_unicode_U+1FFFE_nonchar.json │ │ ├── y_string_unicode_U+2064_invisible_plus.json │ │ ├── y_string_unicode_escaped_double_quote.json │ │ ├── i_string_inverted_surrogates_U+1D11E.json │ │ ├── n_number_with_alpha_char.json │ │ ├── n_object_with_single_string.json │ │ ├── n_string_1_surrogate_then_escape_u1x.json │ │ ├── n_structure_comma_instead_of_closing_brace.json │ │ ├── n_structure_object_with_comment.json │ │ ├── n_structure_open_object_string_with_apostrophes.json │ │ ├── n_structure_unclosed_array_partial_null.json │ │ ├── y_object_duplicated_key_and_value.json │ │ ├── y_string_allowed_escapes.json │ │ ├── y_string_unicode_U+10FFFE_nonchar.json │ │ ├── y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json │ │ ├── i_number_too_big_neg_int.json │ │ ├── i_string_1st_valid_surrogate_2nd_invalid.json │ │ ├── i_string_incomplete_surrogate_and_escape_valid.json │ │ ├── n_object_trailing_comment_slash_open_incomplete.json │ │ ├── n_structure_object_with_trailing_garbage.json │ │ ├── n_structure_unclosed_array_unfinished_false.json │ │ ├── n_structure_unclosed_array_unfinished_true.json │ │ ├── y_string_1_2_3_bytes_UTF-8_sequences.json │ │ ├── i_string_incomplete_surrogates_escape_valid.json │ │ ├── n_object_non_string_key_but_huge_number_instead.json │ │ ├── n_string_incomplete_surrogate_escape_invalid.json │ │ ├── y_object_extreme_numbers.json │ │ ├── y_string_accepted_surrogate_pairs.json │ │ ├── y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json │ │ ├── i_number_very_big_negative_int.json │ │ ├── y_number_double_close_to_zero.json │ │ ├── i_string_iso_latin_1.json │ │ ├── n_array_invalid_utf8.json │ │ ├── y_object_long_strings.json │ │ ├── y_object_string_unicode.json │ │ ├── i_string_invalid_utf-8.json │ │ ├── i_string_utf16BE_no_BOM.json │ │ ├── i_string_utf16LE_no_BOM.json │ │ ├── n_array_a_invalid_utf8.json │ │ ├── i_string_UTF-16LE_with_BOM.json │ │ ├── i_string_truncated-utf-8.json │ │ ├── n_structure_single_eacute.json │ │ ├── i_string_UTF-8_invalid_sequence.json │ │ ├── i_string_UTF8_surrogate_U+D800.json │ │ ├── i_string_not_in_unicode_range.json │ │ ├── n_number_invalid-utf-8-in-int.json │ │ ├── n_structure_incomplete_UTF8_BOM.json │ │ ├── n_structure_lone-invalid-utf-8.json │ │ ├── i_number_huge_exp.json │ │ ├── n_string_invalid-utf-8-in-escape.json │ │ ├── i_string_lone_utf8_continuation_byte.json │ │ ├── i_string_overlong_sequence_2_bytes.json │ │ ├── i_string_overlong_sequence_6_bytes.json │ │ ├── n_number_invalid-utf-8-in-bigger-int.json │ │ ├── n_number_invalid-utf-8-in-exponent.json │ │ ├── n_string_invalid_utf8_after_escape.json │ │ ├── i_string_overlong_sequence_6_bytes_null.json │ │ ├── n_number_real_with_invalid_utf8_after_e.json │ │ ├── n_object_lone_continuation_byte_in_key_and_trailing_comma.json │ │ └── i_structure_500_nested_arrays.json │ ├── test_transform │ │ ├── number_1.0.json │ │ ├── number_1e6.json │ │ ├── number_1e-999.json │ │ ├── string_with_escaped_NULL.json │ │ ├── object_key_nfc_nfd.json │ │ ├── object_key_nfd_nfc.json │ │ ├── object_same_key_same_value.json │ │ ├── number_1000000000000000.json │ │ ├── object_same_key_different_values.json │ │ ├── string_1_escaped_invalid_codepoint.json │ │ ├── object_same_key_unclear_values.json │ │ ├── string_2_escaped_invalid_codepoints.json │ │ ├── number_-9223372036854775808.json │ │ ├── number_-9223372036854775809.json │ │ ├── number_1.000000000000000005.json │ │ ├── number_10000000000000000999.json │ │ ├── number_9223372036854775807.json │ │ ├── number_9223372036854775808.json │ │ ├── string_3_escaped_invalid_codepoints.json │ │ ├── string_1_invalid_codepoint.json │ │ ├── string_2_invalid_codepoints.json │ │ ├── string_3_invalid_codepoints.json │ │ └── README.md │ └── README.md ├── native_json_benchmark │ ├── jsonchecker │ │ ├── fail29.json │ │ ├── fail30.json │ │ ├── fail31.json │ │ ├── fail16.json │ │ ├── fail33.json │ │ ├── fail02.json │ │ ├── fail04.json │ │ ├── fail08.json │ │ ├── fail24.json │ │ ├── fail09.json │ │ ├── fail19.json │ │ ├── fail23.json │ │ ├── fail27.json │ │ ├── fail28.json │ │ ├── fail05.json │ │ ├── fail06.json │ │ ├── fail07.json │ │ ├── fail20.json │ │ ├── fail11.json │ │ ├── fail12.json │ │ ├── fail14.json │ │ ├── fail21.json │ │ ├── fail25.json │ │ ├── fail03.json │ │ ├── fail15.json │ │ ├── fail17.json │ │ ├── fail22.json │ │ ├── fail26.json │ │ ├── fail32.json │ │ ├── fail13.json │ │ ├── pass02.json │ │ ├── fail10.json │ │ ├── fail18_EXCLUDE.json │ │ ├── fail01_EXCLUDE.json │ │ ├── pass03.json │ │ ├── readme.txt │ │ └── pass01.json │ ├── roundtrip │ │ ├── roundtrip04.json │ │ ├── roundtrip06.json │ │ ├── roundtrip07.json │ │ ├── roundtrip11.json │ │ ├── roundtrip15.json │ │ ├── roundtrip01.json │ │ ├── roundtrip02.json │ │ ├── roundtrip03.json │ │ ├── roundtrip05.json │ │ ├── roundtrip08.json │ │ ├── roundtrip20.json │ │ ├── roundtrip21.json │ │ ├── roundtrip22.json │ │ ├── roundtrip23.json │ │ ├── roundtrip24.json │ │ ├── roundtrip09.json │ │ ├── roundtrip12.json │ │ ├── roundtrip16.json │ │ ├── roundtrip17.json │ │ ├── roundtrip10.json │ │ ├── roundtrip13.json │ │ ├── roundtrip14.json │ │ ├── roundtrip18.json │ │ ├── roundtrip19.json │ │ ├── roundtrip25.json │ │ ├── roundtrip27.json │ │ └── roundtrip26.json │ └── data.txt ├── test_version.py ├── test_blns.py ├── test_benchmark.py ├── example_consts.py ├── test_unit_tests │ ├── test_comment_lexer.py │ ├── test_identifier_lexer.py │ ├── test_lexer.py │ └── test_number_lexer.py ├── test_json_test_suit.py ├── test_json5_examples.py ├── test_native_json_benchmark.py └── test_cli.py ├── src └── ujson5 │ ├── py.typed │ ├── __init__.py │ ├── core.py │ └── consts.py ├── docs ├── about.md ├── api_reference │ ├── core.md │ ├── decoder.md │ └── encoder.md ├── contributing.md └── start_decoding.md ├── mypy.ini ├── .isort.cfg ├── .bandit ├── .markdownlint.yaml ├── .trunk ├── .gitignore └── trunk.yaml ├── .yamllint.yaml ├── ruff.toml ├── .gitignore ├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.yml │ └── bug.yml └── workflows │ ├── formatters.yml │ ├── docs.yml │ ├── mypy.yml │ ├── benchmark.yml │ ├── flake8.yml │ ├── pylint.yml │ ├── release.yml │ ├── deploy_docs.yml │ └── CI.yml ├── release ├── shared.py └── README.md ├── ujson5.code-workspace ├── LICENSE ├── cspell.json ├── CHANGELOG.md ├── .pylintrc ├── Makefile ├── mkdocs.yml ├── .pre-commit-config.yaml └── pyproject.toml /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ujson5/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/about.md: -------------------------------------------------------------------------------- 1 | # About 2 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | 2 | [mypy] 3 | -------------------------------------------------------------------------------- /tests/test_snapshots/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/json5_examples/misc/empty.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | profile=black 3 | -------------------------------------------------------------------------------- /tests/json5_examples/arrays/empty-array.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /tests/json5_examples/numbers/float.json: -------------------------------------------------------------------------------- 1 | 1.2 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer.json: -------------------------------------------------------------------------------- 1 | 15 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/nan.json5: -------------------------------------------------------------------------------- 1 | NaN 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/noctal.js: -------------------------------------------------------------------------------- 1 | 080 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/octal.txt: -------------------------------------------------------------------------------- 1 | 010 2 | -------------------------------------------------------------------------------- /tests/json5_examples/objects/empty-object.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tests/json5_examples/numbers/zero-float.json: -------------------------------------------------------------------------------- 1 | 0.0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/zero-integer.json: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/zero-octal.txt: -------------------------------------------------------------------------------- 1 | 00 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/hexadecimal-empty.txt: -------------------------------------------------------------------------------- 1 | 0x 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/hexadecimal.json5: -------------------------------------------------------------------------------- 1 | 0xC8 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/infinity.json5: -------------------------------------------------------------------------------- 1 | Infinity 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/lone-decimal-point.txt: -------------------------------------------------------------------------------- 1 | . 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-float.json: -------------------------------------------------------------------------------- 1 | -1.2 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-integer.json: -------------------------------------------------------------------------------- 1 | -15 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-noctal.js: -------------------------------------------------------------------------------- 1 | -098 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-octal.txt: -------------------------------------------------------------------------------- 1 | -0123 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-float.json5: -------------------------------------------------------------------------------- 1 | +1.2 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-noctal.js: -------------------------------------------------------------------------------- 1 | +098 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-octal.txt: -------------------------------------------------------------------------------- 1 | +0123 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_+1.json: -------------------------------------------------------------------------------- 1 | [+1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_-01.json: -------------------------------------------------------------------------------- 1 | [-01] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_-2..json: -------------------------------------------------------------------------------- 1 | [-2.] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_.-1.json: -------------------------------------------------------------------------------- 1 | [.-1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_0e+.json: -------------------------------------------------------------------------------- 1 | [0e+] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_0e.json: -------------------------------------------------------------------------------- 1 | [0e] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_Inf.json: -------------------------------------------------------------------------------- 1 | [Inf] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_NaN.json: -------------------------------------------------------------------------------- 1 | [NaN] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_single_space.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_array_empty.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_array_null.json: -------------------------------------------------------------------------------- 1 | [null] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number.json: -------------------------------------------------------------------------------- 1 | [123e65] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_0e1.json: -------------------------------------------------------------------------------- 1 | [0e1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object_empty.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_pi.json: -------------------------------------------------------------------------------- 1 | ["π"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_space.json: -------------------------------------------------------------------------------- 1 | " " -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail29.json: -------------------------------------------------------------------------------- 1 | [0e] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail30.json: -------------------------------------------------------------------------------- 1 | [0e+] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail31.json: -------------------------------------------------------------------------------- 1 | [0e+-1] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip04.json: -------------------------------------------------------------------------------- 1 | [0] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip06.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip07.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip11.json: -------------------------------------------------------------------------------- 1 | [-1] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip15.json: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /tests/json5_examples/numbers/float-leading-zero.json: -------------------------------------------------------------------------------- 1 | 0.5 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-zero-float.json: -------------------------------------------------------------------------------- 1 | -0.0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-zero-integer.json: -------------------------------------------------------------------------------- 1 | -0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-zero-octal.txt: -------------------------------------------------------------------------------- 1 | -00 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-integer.json5: -------------------------------------------------------------------------------- 1 | +15 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-zero-float.json5: -------------------------------------------------------------------------------- 1 | +0.0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-zero-integer.json5: -------------------------------------------------------------------------------- 1 | +0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-zero-octal.txt: -------------------------------------------------------------------------------- 1 | +00 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/zero-hexadecimal.json5: -------------------------------------------------------------------------------- 1 | 0x0 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_incomplete.json: -------------------------------------------------------------------------------- 1 | ["x" -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_just_comma.json: -------------------------------------------------------------------------------- 1 | [,] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_just_minus.json: -------------------------------------------------------------------------------- 1 | [-] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_star_inside.json: -------------------------------------------------------------------------------- 1 | [*] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_unclosed.json: -------------------------------------------------------------------------------- 1 | ["" -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_incomplete_null.json: -------------------------------------------------------------------------------- 1 | [nul] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_incomplete_true.json: -------------------------------------------------------------------------------- 1 | [tru] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_++.json: -------------------------------------------------------------------------------- 1 | [++1234] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_+Inf.json: -------------------------------------------------------------------------------- 1 | [+Inf] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_-1.0..json: -------------------------------------------------------------------------------- 1 | [-1.0.] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_-NaN.json: -------------------------------------------------------------------------------- 1 | [-NaN] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_.2e-3.json: -------------------------------------------------------------------------------- 1 | [.2e-3] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_0.1.2.json: -------------------------------------------------------------------------------- 1 | [0.1.2] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_0.3e+.json: -------------------------------------------------------------------------------- 1 | [0.3e+] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_0.3e.json: -------------------------------------------------------------------------------- 1 | [0.3e] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_0.e1.json: -------------------------------------------------------------------------------- 1 | [0.e1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_1.0e+.json: -------------------------------------------------------------------------------- 1 | [1.0e+] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_1.0e-.json: -------------------------------------------------------------------------------- 1 | [1.0e-] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_1.0e.json: -------------------------------------------------------------------------------- 1 | [1.0e] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_1_000.json: -------------------------------------------------------------------------------- 1 | [1 000.0] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_1eE2.json: -------------------------------------------------------------------------------- 1 | [1eE2] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_2.e+3.json: -------------------------------------------------------------------------------- 1 | [2.e+3] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_2.e-3.json: -------------------------------------------------------------------------------- 1 | [2.e-3] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_2.e3.json: -------------------------------------------------------------------------------- 1 | [2.e3] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_9.e+.json: -------------------------------------------------------------------------------- 1 | [9.e+] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_emoji.json: -------------------------------------------------------------------------------- 1 | {🇨🇭} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_no-colon.json: -------------------------------------------------------------------------------- 1 | {"a" -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_end_array.json: -------------------------------------------------------------------------------- 1 | ] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_no_data.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_array_false.json: -------------------------------------------------------------------------------- 1 | [false] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_0e+1.json: -------------------------------------------------------------------------------- 1 | [0e+1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_minus_zero.json: -------------------------------------------------------------------------------- 1 | [-0] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object_simple.json: -------------------------------------------------------------------------------- 1 | {"a":[]} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_utf8.json: -------------------------------------------------------------------------------- 1 | ["€𝄞"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/number_1.0.json: -------------------------------------------------------------------------------- 1 | [1.0] 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/number_1e6.json: -------------------------------------------------------------------------------- 1 | [1E6] 2 | -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail16.json: -------------------------------------------------------------------------------- 1 | [\naked] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail33.json: -------------------------------------------------------------------------------- 1 | ["mismatch"} -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip01.json: -------------------------------------------------------------------------------- 1 | [null] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip02.json: -------------------------------------------------------------------------------- 1 | [true] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip03.json: -------------------------------------------------------------------------------- 1 | [false] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip05.json: -------------------------------------------------------------------------------- 1 | ["foo"] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip08.json: -------------------------------------------------------------------------------- 1 | [0,1] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip20.json: -------------------------------------------------------------------------------- 1 | [0.0] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip21.json: -------------------------------------------------------------------------------- 1 | [-0.0] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip22.json: -------------------------------------------------------------------------------- 1 | [1.2345] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip23.json: -------------------------------------------------------------------------------- 1 | [-1.2345] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip24.json: -------------------------------------------------------------------------------- 1 | [5e-324] -------------------------------------------------------------------------------- /.bandit: -------------------------------------------------------------------------------- 1 | [bandit] 2 | exclude = release 3 | skips = B101,B311 4 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/hexadecimal-uppercase-x.json5: -------------------------------------------------------------------------------- 1 | 0XC8 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-hexadecimal.json5: -------------------------------------------------------------------------------- 1 | -0xC8 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-infinity.json5: -------------------------------------------------------------------------------- 1 | -Infinity 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-hexadecimal.json5: -------------------------------------------------------------------------------- 1 | +0xC8 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-infinity.json5: -------------------------------------------------------------------------------- 1 | +Infinity 2 | -------------------------------------------------------------------------------- /tests/json5_examples/strings/single-quoted-string.json5: -------------------------------------------------------------------------------- 1 | 'hello world' -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_comma_and_number.json: -------------------------------------------------------------------------------- 1 | [,1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_double_comma.json: -------------------------------------------------------------------------------- 1 | [1,,2] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_extra_close.json: -------------------------------------------------------------------------------- 1 | ["x"]] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_extra_comma.json: -------------------------------------------------------------------------------- 1 | ["",] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_number_and_comma.json: -------------------------------------------------------------------------------- 1 | [1,] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_incomplete_false.json: -------------------------------------------------------------------------------- 1 | [fals] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_0_capital_E+.json: -------------------------------------------------------------------------------- 1 | [0E+] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_0_capital_E.json: -------------------------------------------------------------------------------- 1 | [0E] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_expression.json: -------------------------------------------------------------------------------- 1 | [1+2] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_hex_1_digit.json: -------------------------------------------------------------------------------- 1 | [0x1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_hex_2_digits.json: -------------------------------------------------------------------------------- 1 | [0x42] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_infinity.json: -------------------------------------------------------------------------------- 1 | [Infinity] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_invalid+-.json: -------------------------------------------------------------------------------- 1 | [0e+-1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_minus_space_1.json: -------------------------------------------------------------------------------- 1 | [- 1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_with_alpha.json: -------------------------------------------------------------------------------- 1 | [1.2a-3] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_missing_key.json: -------------------------------------------------------------------------------- 1 | {:"b"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_missing_value.json: -------------------------------------------------------------------------------- 1 | {"a": -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_non_string_key.json: -------------------------------------------------------------------------------- 1 | {1:1} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_single_quote.json: -------------------------------------------------------------------------------- 1 | {'a':0} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_backslash_00.json: -------------------------------------------------------------------------------- 1 | ["\"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_escape_x.json: -------------------------------------------------------------------------------- 1 | ["\x00"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_single_doublequote.json: -------------------------------------------------------------------------------- 1 | " -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_unescaped_tab.json: -------------------------------------------------------------------------------- 1 | [" "] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_UTF8_BOM_no_data.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_double_array.json: -------------------------------------------------------------------------------- 1 | [][] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_object.json: -------------------------------------------------------------------------------- 1 | { -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_single_star.json: -------------------------------------------------------------------------------- 1 | * -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_unclosed_array.json: -------------------------------------------------------------------------------- 1 | [1 -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_array_empty-string.json: -------------------------------------------------------------------------------- 1 | [""] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_after_space.json: -------------------------------------------------------------------------------- 1 | [ 4] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_int_with_exp.json: -------------------------------------------------------------------------------- 1 | [20e1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_negative_int.json: -------------------------------------------------------------------------------- 1 | [-123] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_negative_one.json: -------------------------------------------------------------------------------- 1 | [-1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_negative_zero.json: -------------------------------------------------------------------------------- 1 | [-0] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_real_neg_exp.json: -------------------------------------------------------------------------------- 1 | [1e-2] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_simple_int.json: -------------------------------------------------------------------------------- 1 | [123] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object_basic.json: -------------------------------------------------------------------------------- 1 | {"asd":"sdf"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object_empty_key.json: -------------------------------------------------------------------------------- 1 | {"":0} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_in_array.json: -------------------------------------------------------------------------------- 1 | ["asd"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_u+2029_par_sep.json: -------------------------------------------------------------------------------- 1 | ["
"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_unicode.json: -------------------------------------------------------------------------------- 1 | ["\uA66D"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_unicode_2.json: -------------------------------------------------------------------------------- 1 | ["⍂㈴⍂"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_structure_lonely_int.json: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_structure_lonely_null.json: -------------------------------------------------------------------------------- 1 | null -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_structure_lonely_true.json: -------------------------------------------------------------------------------- 1 | true -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_structure_string_empty.json: -------------------------------------------------------------------------------- 1 | "" -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/number_1e-999.json: -------------------------------------------------------------------------------- 1 | [1E-999] 2 | -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail02.json: -------------------------------------------------------------------------------- 1 | ["Unclosed array" -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail04.json: -------------------------------------------------------------------------------- 1 | ["extra comma",] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail08.json: -------------------------------------------------------------------------------- 1 | ["Extra close"]] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail24.json: -------------------------------------------------------------------------------- 1 | ['single quote'] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip09.json: -------------------------------------------------------------------------------- 1 | {"foo":"bar"} -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip12.json: -------------------------------------------------------------------------------- 1 | [-2147483648] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip16.json: -------------------------------------------------------------------------------- 1 | [2147483647] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip17.json: -------------------------------------------------------------------------------- 1 | [4294967295] -------------------------------------------------------------------------------- /tests/json5_examples/arrays/leading-comma-array.js: -------------------------------------------------------------------------------- 1 | [ 2 | ,null 3 | ] -------------------------------------------------------------------------------- /tests/json5_examples/arrays/lone-trailing-comma-array.js: -------------------------------------------------------------------------------- 1 | [ 2 | , 3 | ] -------------------------------------------------------------------------------- /tests/json5_examples/numbers/float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | .5 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | 5. 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/float-with-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 1.2e3 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/hexadecimal-lowercase-letter.json5: -------------------------------------------------------------------------------- 1 | 0xc8 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-float-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e2.3 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 2e23 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-float-leading-zero.json: -------------------------------------------------------------------------------- 1 | -0.5 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-zero-hexadecimal.json5: -------------------------------------------------------------------------------- 1 | -0x0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/noctal-with-leading-octal-digit.js: -------------------------------------------------------------------------------- 1 | 0780 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-float-leading-zero.json5: -------------------------------------------------------------------------------- 1 | +0.5 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-zero-hexadecimal.json5: -------------------------------------------------------------------------------- 1 | +0x0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/objects/no-colon-object.txt: -------------------------------------------------------------------------------- 1 | { 2 | foo "bar" 3 | } -------------------------------------------------------------------------------- /tests/json5_examples/strings/multi-line-string.json5: -------------------------------------------------------------------------------- 1 | 'hello\ 2 | world' -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_comma_after_close.json: -------------------------------------------------------------------------------- 1 | [""], -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_double_extra_comma.json: -------------------------------------------------------------------------------- 1 | ["x",,] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_missing_value.json: -------------------------------------------------------------------------------- 1 | [ , ""] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_multidigit_number_then_00.json: -------------------------------------------------------------------------------- 1 | 123 -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_starting_with_dot.json: -------------------------------------------------------------------------------- 1 | [.123] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_with_leading_zero.json: -------------------------------------------------------------------------------- 1 | [012] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_bad_value.json: -------------------------------------------------------------------------------- 1 | ["x", truth] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_bracket_key.json: -------------------------------------------------------------------------------- 1 | {[: "x"} 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_double_colon.json: -------------------------------------------------------------------------------- 1 | {"x"::"b"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_missing_colon.json: -------------------------------------------------------------------------------- 1 | {"a" b} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_trailing_comma.json: -------------------------------------------------------------------------------- 1 | {"id":0,} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_unquoted_key.json: -------------------------------------------------------------------------------- 1 | {a: "b"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_escaped_emoji.json: -------------------------------------------------------------------------------- 1 | ["\🌀"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_incomplete_escape.json: -------------------------------------------------------------------------------- 1 | ["\"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_start_escape_unclosed.json: -------------------------------------------------------------------------------- 1 | ["\ -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_unicode_CapitalU.json: -------------------------------------------------------------------------------- 1 | "\UA66D" -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | ""x -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_U+2060_word_joined.json: -------------------------------------------------------------------------------- 1 | [⁠] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_angle_bracket_..json: -------------------------------------------------------------------------------- 1 | <.> -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_lone-open-bracket.json: -------------------------------------------------------------------------------- 1 | [ -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_array_comma.json: -------------------------------------------------------------------------------- 1 | [, -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_array_string.json: -------------------------------------------------------------------------------- 1 | ["a" -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_object_comma.json: -------------------------------------------------------------------------------- 1 | {, -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_unicode-identifier.json: -------------------------------------------------------------------------------- 1 | å -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_array_arraysWithSpaces.json: -------------------------------------------------------------------------------- 1 | [[] ] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_array_ending_with_newline.json: -------------------------------------------------------------------------------- 1 | ["a"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_array_with_leading_space.json: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_array_with_trailing_space.json: -------------------------------------------------------------------------------- 1 | [2] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_real_capital_e.json: -------------------------------------------------------------------------------- 1 | [1E22] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_real_exponent.json: -------------------------------------------------------------------------------- 1 | [123e45] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_real_pos_exponent.json: -------------------------------------------------------------------------------- 1 | [1e+2] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_simple_real.json: -------------------------------------------------------------------------------- 1 | [123.456789] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_double_escape_a.json: -------------------------------------------------------------------------------- 1 | ["\\a"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_double_escape_n.json: -------------------------------------------------------------------------------- 1 | ["\\n"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_null_escape.json: -------------------------------------------------------------------------------- 1 | ["\u0000"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_one-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u002c"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_simple_ascii.json: -------------------------------------------------------------------------------- 1 | ["asd "] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_two-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u0123"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_u+2028_line_sep.json: -------------------------------------------------------------------------------- 1 | ["
"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_structure_lonely_false.json: -------------------------------------------------------------------------------- 1 | false -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_structure_lonely_string.json: -------------------------------------------------------------------------------- 1 | "asd" -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_structure_true_in_array.json: -------------------------------------------------------------------------------- 1 | [true] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_structure_whitespace_array.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail09.json: -------------------------------------------------------------------------------- 1 | {"Extra comma": true,} -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail19.json: -------------------------------------------------------------------------------- 1 | {"Missing colon" null} -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail23.json: -------------------------------------------------------------------------------- 1 | ["Bad value", truth] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail27.json: -------------------------------------------------------------------------------- 1 | ["line 2 | break"] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail28.json: -------------------------------------------------------------------------------- 1 | ["line\ 2 | break"] -------------------------------------------------------------------------------- /tests/json5_examples/arrays/trailing-comma-array.json5: -------------------------------------------------------------------------------- 1 | [ 2 | null, 3 | ] -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-hexadecimal-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e0x4 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-zero-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 5e0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/zero-float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | .0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/zero-float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | 0. 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/zero-integer-with-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 0e23 2 | -------------------------------------------------------------------------------- /tests/json5_examples/objects/lone-trailing-comma-object.txt: -------------------------------------------------------------------------------- 1 | { 2 | , 3 | } -------------------------------------------------------------------------------- /tests/json5_examples/strings/escaped-single-quoted-string.json5: -------------------------------------------------------------------------------- 1 | 'I can\'t wait' -------------------------------------------------------------------------------- /tests/json5_examples/strings/unescaped-multi-line-string.txt: -------------------------------------------------------------------------------- 1 | "foo 2 | bar" 3 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_number_neg_int_huge_exp.json: -------------------------------------------------------------------------------- 1 | [-1e+9999] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_number_real_underflow.json: -------------------------------------------------------------------------------- 1 | [123e-10000000] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_structure_UTF-8_BOM_empty_object.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_1_true_without_comma.json: -------------------------------------------------------------------------------- 1 | [1 true] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_colon_instead_of_comma.json: -------------------------------------------------------------------------------- 1 | ["": 1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_incomplete_invalid_value.json: -------------------------------------------------------------------------------- 1 | [x -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_inner_array_no_comma.json: -------------------------------------------------------------------------------- 1 | [3[4]] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_number_and_several_commas.json: -------------------------------------------------------------------------------- 1 | [1,,] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_unclosed_trailing_comma.json: -------------------------------------------------------------------------------- 1 | [1, -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_unclosed_with_object_inside.json: -------------------------------------------------------------------------------- 1 | [{} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_U+FF11_fullwidth_digit_one.json: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_minus_infinity.json: -------------------------------------------------------------------------------- 1 | [-Infinity] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_neg_with_garbage_at_end.json: -------------------------------------------------------------------------------- 1 | [-1x] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_real_garbage_after_e.json: -------------------------------------------------------------------------------- 1 | [1ea] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_garbage_at_end.json: -------------------------------------------------------------------------------- 1 | {"a":"a" 123} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_missing_semicolon.json: -------------------------------------------------------------------------------- 1 | {"a" "b"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_trailing_comment.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/**/ -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_unterminated-value.json: -------------------------------------------------------------------------------- 1 | {"a":"a -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_accentuated_char_no_quotes.json: -------------------------------------------------------------------------------- 1 | [é] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_escaped_backslash_bad.json: -------------------------------------------------------------------------------- 1 | ["\\\"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_escaped_ctrl_char_tab.json: -------------------------------------------------------------------------------- 1 | ["\ "] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_invalid_backslash_esc.json: -------------------------------------------------------------------------------- 1 | ["\a"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_no_quotes_with_bad_escape.json: -------------------------------------------------------------------------------- 1 | [\n] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_single_quote.json: -------------------------------------------------------------------------------- 1 | ['single quote'] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_unescaped_ctrl_char.json: -------------------------------------------------------------------------------- 1 | ["aa"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_angle_bracket_null.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_array_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | [1]x -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_ascii-unicode-identifier.json: -------------------------------------------------------------------------------- 1 | aå -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_capitalized_True.json: -------------------------------------------------------------------------------- 1 | [True] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_close_unopened_array.json: -------------------------------------------------------------------------------- 1 | 1] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_array_apostrophe.json: -------------------------------------------------------------------------------- 1 | [' -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_array_open_object.json: -------------------------------------------------------------------------------- 1 | [{ -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_array_open_string.json: -------------------------------------------------------------------------------- 1 | ["a -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_object_close_array.json: -------------------------------------------------------------------------------- 1 | {] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_object_open_array.json: -------------------------------------------------------------------------------- 1 | {[ -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_object_open_string.json: -------------------------------------------------------------------------------- 1 | {"a -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_open.json: -------------------------------------------------------------------------------- 1 | ["\{["\{["\{["\{ -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_trailing_#.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}#{} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_whitespace_formfeed.json: -------------------------------------------------------------------------------- 1 | [ ] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_array_with_1_and_newline.json: -------------------------------------------------------------------------------- 1 | [1 2 | ] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_real_capital_e_neg_exp.json: -------------------------------------------------------------------------------- 1 | [1E-2] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_real_capital_e_pos_exp.json: -------------------------------------------------------------------------------- 1 | [1E+2] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object.json: -------------------------------------------------------------------------------- 1 | {"asd":"sdf", "dfg":"fgh"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_backslash_doublequotes.json: -------------------------------------------------------------------------------- 1 | ["\""] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_comments.json: -------------------------------------------------------------------------------- 1 | ["a/*b*/c/*d//e"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_three-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u0821"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_unescaped_char_delete.json: -------------------------------------------------------------------------------- 1 | [""] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_with_del_character.json: -------------------------------------------------------------------------------- 1 | ["aa"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_structure_lonely_negative_real.json: -------------------------------------------------------------------------------- 1 | -0.1 -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_structure_trailing_newline.json: -------------------------------------------------------------------------------- 1 | ["a"] 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/string_with_escaped_NULL.json: -------------------------------------------------------------------------------- 1 | ["A\u0000B"] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail05.json: -------------------------------------------------------------------------------- 1 | ["double extra comma",,] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail06.json: -------------------------------------------------------------------------------- 1 | [ , "<-- missing value"] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail07.json: -------------------------------------------------------------------------------- 1 | ["Comma after the close"], -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail20.json: -------------------------------------------------------------------------------- 1 | {"Double colon":: null} -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip10.json: -------------------------------------------------------------------------------- 1 | {"a":null,"foo":"bar"} -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip13.json: -------------------------------------------------------------------------------- 1 | [-1234567890123456789] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip14.json: -------------------------------------------------------------------------------- 1 | [-9223372036854775808] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip18.json: -------------------------------------------------------------------------------- 1 | [1234567890123456789] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip19.json: -------------------------------------------------------------------------------- 1 | [9223372036854775807] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip25.json: -------------------------------------------------------------------------------- 1 | [2.225073858507201e-308] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip27.json: -------------------------------------------------------------------------------- 1 | [1.7976931348623157e308] -------------------------------------------------------------------------------- /tests/json5_examples/arrays/no-comma-array.txt: -------------------------------------------------------------------------------- 1 | [ 2 | true 3 | false 4 | ] -------------------------------------------------------------------------------- /tests/json5_examples/numbers/hexadecimal-with-integer-exponent.json5: -------------------------------------------------------------------------------- 1 | 0xc8e4 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-negative-float-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e-2.3 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-negative-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 2e-23 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-positive-float-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e+2.3 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-positive-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 1e+2 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | -.5 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | -5. 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | +.5 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | +5. 2 | -------------------------------------------------------------------------------- /tests/json5_examples/objects/leading-comma-object.txt: -------------------------------------------------------------------------------- 1 | { 2 | ,"foo": "bar" 3 | } -------------------------------------------------------------------------------- /tests/json5_examples/objects/reserved-unquoted-key.json5: -------------------------------------------------------------------------------- 1 | { 2 | while: true 3 | } -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_number_double_huge_neg_exp.json: -------------------------------------------------------------------------------- 1 | [123.456e-789] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_number_pos_double_huge_exp.json: -------------------------------------------------------------------------------- 1 | [1.5e+9999] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_number_real_neg_overflow.json: -------------------------------------------------------------------------------- 1 | [-123123e100000] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_number_real_pos_overflow.json: -------------------------------------------------------------------------------- 1 | [123123e100000] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_object_key_lone_2nd_surrogate.json: -------------------------------------------------------------------------------- 1 | {"\uDFAA":0} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_invalid_lonely_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\ud800"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_invalid_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\ud800abc"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_lone_second_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\uDFAA"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_items_separated_by_semicolon.json: -------------------------------------------------------------------------------- 1 | [1:2] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_invalid-negative-real.json: -------------------------------------------------------------------------------- 1 | [-123.123foo] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_neg_int_starting_with_zero.json: -------------------------------------------------------------------------------- 1 | [-012] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_neg_real_without_int_part.json: -------------------------------------------------------------------------------- 1 | [-.123] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_real_without_fractional_part.json: -------------------------------------------------------------------------------- 1 | [1.] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_comma_instead_of_colon.json: -------------------------------------------------------------------------------- 1 | {"x", null} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}# -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_1_surrogate_then_escape.json: -------------------------------------------------------------------------------- 1 | ["\uD800\"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_incomplete_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\uD834\uDd"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_invalid_unicode_escape.json: -------------------------------------------------------------------------------- 1 | ["\uqqqq"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_single_string_no_double_quotes.json: -------------------------------------------------------------------------------- 1 | abc -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_unescaped_newline.json: -------------------------------------------------------------------------------- 1 | ["new 2 | line"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_null-byte-outside-string.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_number_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | 2@ -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_object_unclosed_no_value.json: -------------------------------------------------------------------------------- 1 | {"": -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_unclosed_object.json: -------------------------------------------------------------------------------- 1 | {"asd":"asd" -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_array_heterogeneous.json: -------------------------------------------------------------------------------- 1 | [null, 1, "1", {}] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_real_fraction_exponent.json: -------------------------------------------------------------------------------- 1 | [123.456e78] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object_duplicated_key.json: -------------------------------------------------------------------------------- 1 | {"a":"b","a":"c"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object_with_newlines.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": "b" 3 | } -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_escaped_noncharacter.json: -------------------------------------------------------------------------------- 1 | ["\uFFFF"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_nbsp_uescaped.json: -------------------------------------------------------------------------------- 1 | ["new\u00A0line"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json: -------------------------------------------------------------------------------- 1 | ["􏿿"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.json: -------------------------------------------------------------------------------- 1 | ["￿"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_uescaped_newline.json: -------------------------------------------------------------------------------- 1 | ["new\u000Aline"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_unicodeEscapedBackslash.json: -------------------------------------------------------------------------------- 1 | ["\u005C"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_unicode_U+FDD0_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uFDD0"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_unicode_U+FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uFFFE"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/object_key_nfc_nfd.json: -------------------------------------------------------------------------------- 1 | {"é":"NFC","é":"NFD"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/object_key_nfd_nfc.json: -------------------------------------------------------------------------------- 1 | {"é":"NFD","é":"NFC"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/object_same_key_same_value.json: -------------------------------------------------------------------------------- 1 | {"a":1,"a":1} -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail11.json: -------------------------------------------------------------------------------- 1 | {"Illegal expression": 1 + 2} -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail12.json: -------------------------------------------------------------------------------- 1 | {"Illegal invocation": alert()} -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail14.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot be hex": 0x14} -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail21.json: -------------------------------------------------------------------------------- 1 | {"Comma instead of colon", null} -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail25.json: -------------------------------------------------------------------------------- 1 | [" tab character in string "] -------------------------------------------------------------------------------- /tests/native_json_benchmark/roundtrip/roundtrip26.json: -------------------------------------------------------------------------------- 1 | [2.2250738585072014e-308] -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-negative-hexadecimal-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e-0x4 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-negative-zero-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 5e-0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-positive-hexadecimal-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e+0x4 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/integer-with-positive-zero-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 5e+0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-zero-float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | -.0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/negative-zero-float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | -0. 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-zero-float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | +.0 2 | -------------------------------------------------------------------------------- /tests/json5_examples/numbers/positive-zero-float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | +0. 2 | -------------------------------------------------------------------------------- /tests/json5_examples/objects/single-quoted-key.json5: -------------------------------------------------------------------------------- 1 | { 2 | 'hello': "world" 3 | } -------------------------------------------------------------------------------- /tests/json5_examples/objects/trailing-comma-object.json5: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | } -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_number_too_big_pos_int.json: -------------------------------------------------------------------------------- 1 | [100000000000000000000] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_1st_surrogate_but_2nd_missing.json: -------------------------------------------------------------------------------- 1 | ["\uDADA"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_incomplete_surrogate_pair.json: -------------------------------------------------------------------------------- 1 | ["\uDd1ea"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_newlines_unclosed.json: -------------------------------------------------------------------------------- 1 | ["a", 2 | 4 3 | ,1, -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_spaces_vertical_tab_formfeed.json: -------------------------------------------------------------------------------- 1 | [" a"\f] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_unclosed_with_new_lines.json: -------------------------------------------------------------------------------- 1 | [1, 2 | 1 3 | ,1 -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_minus_sign_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | [-foo] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_key_with_single_quotes.json: -------------------------------------------------------------------------------- 1 | {key: 'value'} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_repeated_null_null.json: -------------------------------------------------------------------------------- 1 | {null:null,null:null} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_several_trailing_commas.json: -------------------------------------------------------------------------------- 1 | {"id":0,,,,,} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_trailing_comment_open.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/**// -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_trailing_comment_slash_open.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}// -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_two_commas_in_a_row.json: -------------------------------------------------------------------------------- 1 | {"a":"b",,"c":"d"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_1_surrogate_then_escape_u.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_1_surrogate_then_escape_u1.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u1"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_incomplete_escaped_character.json: -------------------------------------------------------------------------------- 1 | ["\u00A"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_leading_uescaped_thinspace.json: -------------------------------------------------------------------------------- 1 | [\u0020"asd"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_array_with_extra_array_close.json: -------------------------------------------------------------------------------- 1 | [1]] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_array_with_unclosed_string.json: -------------------------------------------------------------------------------- 1 | ["asd] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_object_followed_by_closing_object.json: -------------------------------------------------------------------------------- 1 | {}} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_uescaped_LF_before_string.json: -------------------------------------------------------------------------------- 1 | [\u000A""] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_whitespace_U+2060_word_joiner.json: -------------------------------------------------------------------------------- 1 | [⁠] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_array_with_several_null.json: -------------------------------------------------------------------------------- 1 | [1,null,null,null,2] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object_escaped_null_in_key.json: -------------------------------------------------------------------------------- 1 | {"foo\u0000bar": 42} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_accepted_surrogate_pair.json: -------------------------------------------------------------------------------- 1 | ["\uD801\udc37"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_backslash_and_u_escaped_zero.json: -------------------------------------------------------------------------------- 1 | ["\\u0000"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_escaped_control_character.json: -------------------------------------------------------------------------------- 1 | ["\u0012"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_in_array_with_leading_space.json: -------------------------------------------------------------------------------- 1 | [ "asd"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_last_surrogates_1_and_2.json: -------------------------------------------------------------------------------- 1 | ["\uDBFF\uDFFF"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json: -------------------------------------------------------------------------------- 1 | ["𛿿"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_uEscape.json: -------------------------------------------------------------------------------- 1 | ["\u0061\u30af\u30EA\u30b9"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_unicode_U+1FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uD83F\uDFFE"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_unicode_U+2064_invisible_plus.json: -------------------------------------------------------------------------------- 1 | ["\u2064"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_unicode_escaped_double_quote.json: -------------------------------------------------------------------------------- 1 | ["\u0022"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/number_1000000000000000.json: -------------------------------------------------------------------------------- 1 | [1000000000000000] 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/object_same_key_different_values.json: -------------------------------------------------------------------------------- 1 | {"a":1,"a":2} -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/string_1_escaped_invalid_codepoint.json: -------------------------------------------------------------------------------- 1 | ["\uD800"] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail03.json: -------------------------------------------------------------------------------- 1 | {unquoted_key: "keys must be quoted"} -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail15.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \x15"] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail17.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \017"] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail22.json: -------------------------------------------------------------------------------- 1 | ["Colon instead of comma": false] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_inverted_surrogates_U+1D11E.json: -------------------------------------------------------------------------------- 1 | ["\uDd1e\uD834"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_with_alpha_char.json: -------------------------------------------------------------------------------- 1 | [1.8011670033376514H-308] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_with_single_string.json: -------------------------------------------------------------------------------- 1 | { "foo" : "bar", "a" } -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_1_surrogate_then_escape_u1x.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u1x"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_comma_instead_of_closing_brace.json: -------------------------------------------------------------------------------- 1 | {"x": true, -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_object_with_comment.json: -------------------------------------------------------------------------------- 1 | {"a":/*comment*/"b"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_open_object_string_with_apostrophes.json: -------------------------------------------------------------------------------- 1 | {'a' -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_unclosed_array_partial_null.json: -------------------------------------------------------------------------------- 1 | [ false, nul -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object_duplicated_key_and_value.json: -------------------------------------------------------------------------------- 1 | {"a":"b","a":"b"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_allowed_escapes.json: -------------------------------------------------------------------------------- 1 | ["\"\\\/\b\f\n\r\t"] 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_unicode_U+10FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uDBFF\uDFFE"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json: -------------------------------------------------------------------------------- 1 | ["\u200B"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/object_same_key_unclear_values.json: -------------------------------------------------------------------------------- 1 | {"a":0, "a":-0} 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/string_2_escaped_invalid_codepoints.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800"] -------------------------------------------------------------------------------- /tests/native_json_benchmark/data.txt: -------------------------------------------------------------------------------- 1 | canada.json 2 | citm_catalog.json 3 | twitter.json 4 | -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail26.json: -------------------------------------------------------------------------------- 1 | ["tab\ character\ in\ string\ "] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail32.json: -------------------------------------------------------------------------------- 1 | {"Comma instead if closing brace": true, -------------------------------------------------------------------------------- /tests/json5_examples/arrays/regular-array.json: -------------------------------------------------------------------------------- 1 | [ 2 | true, 3 | false, 4 | null 5 | ] -------------------------------------------------------------------------------- /tests/json5_examples/new-lines/comment-cr.json5: -------------------------------------------------------------------------------- 1 | { // This comment is terminated with `\r`. } -------------------------------------------------------------------------------- /tests/json5_examples/numbers/float-trailing-decimal-point-with-integer-exponent.json5: -------------------------------------------------------------------------------- 1 | 5.e4 2 | -------------------------------------------------------------------------------- /tests/json5_examples/objects/duplicate-keys.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": true, 3 | "a": false 4 | } 5 | -------------------------------------------------------------------------------- /tests/json5_examples/objects/illegal-unquoted-key-number.txt: -------------------------------------------------------------------------------- 1 | { 2 | 10twenty: "ten twenty" 3 | } -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_number_too_big_neg_int.json: -------------------------------------------------------------------------------- 1 | [-123123123123123123123123123123] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_1st_valid_surrogate_2nd_invalid.json: -------------------------------------------------------------------------------- 1 | ["\uD888\u1234"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_incomplete_surrogate_and_escape_valid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\n"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_trailing_comment_slash_open_incomplete.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/ -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_object_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | {"a": true} "x" -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_unclosed_array_unfinished_false.json: -------------------------------------------------------------------------------- 1 | [ true, fals -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_unclosed_array_unfinished_true.json: -------------------------------------------------------------------------------- 1 | [ false, tru -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.json: -------------------------------------------------------------------------------- 1 | ["\u0060\u012a\u12AB"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/number_-9223372036854775808.json: -------------------------------------------------------------------------------- 1 | [-9223372036854775808] 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/number_-9223372036854775809.json: -------------------------------------------------------------------------------- 1 | [-9223372036854775809] 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/number_1.000000000000000005.json: -------------------------------------------------------------------------------- 1 | [1.000000000000000005] 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/number_10000000000000000999.json: -------------------------------------------------------------------------------- 1 | [10000000000000000999] 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/number_9223372036854775807.json: -------------------------------------------------------------------------------- 1 | [9223372036854775807] 2 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/number_9223372036854775808.json: -------------------------------------------------------------------------------- 1 | [9223372036854775808] 2 | -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail13.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot have leading zeroes": 013} -------------------------------------------------------------------------------- /tests/json5_examples/objects/illegal-unquoted-key-symbol.txt: -------------------------------------------------------------------------------- 1 | { 2 | multi-word: "multi-word" 3 | } -------------------------------------------------------------------------------- /tests/json5_examples/objects/no-comma-object.txt: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar" 3 | "hello": "world" 4 | } -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_incomplete_surrogates_escape_valid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\n"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_non_string_key_but_huge_number_instead.json: -------------------------------------------------------------------------------- 1 | {9999E9999:1} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_incomplete_surrogate_escape_invalid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\x"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object_extreme_numbers.json: -------------------------------------------------------------------------------- 1 | { "min": -1.0e+28, "max": 1.0e+28 } -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_accepted_surrogate_pairs.json: -------------------------------------------------------------------------------- 1 | ["\ud83d\ude39\ud83d\udc8d"] -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/string_3_escaped_invalid_codepoints.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\uD800"] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/pass02.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /tests/json5_examples/comments/inline-comment-following-array-element.json5: -------------------------------------------------------------------------------- 1 | [ 2 | false // true 3 | ] -------------------------------------------------------------------------------- /tests/json5_examples/new-lines/comment-lf.json5: -------------------------------------------------------------------------------- 1 | { 2 | // This comment is terminated with `\n`. 3 | } 4 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json: -------------------------------------------------------------------------------- 1 | ["\uD834\uDd1e"] -------------------------------------------------------------------------------- /tests/json5_examples/todo/unicode-escaped-unquoted-key.json5: -------------------------------------------------------------------------------- 1 | { 2 | sig\u03A3ma: "the sum of all things" 3 | } -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail10.json: -------------------------------------------------------------------------------- 1 | {"Extra value after close": true} "misplaced quoted value" -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail18_EXCLUDE.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /tests/json5_examples/comments/block-comment-in-string.json: -------------------------------------------------------------------------------- 1 | "This /* block comment */ isn't really a block comment." -------------------------------------------------------------------------------- /tests/json5_examples/comments/inline-comment-in-string.json: -------------------------------------------------------------------------------- 1 | "This inline comment // isn't really an inline comment." -------------------------------------------------------------------------------- /tests/json5_examples/new-lines/comment-crlf.json5: -------------------------------------------------------------------------------- 1 | { 2 | // This comment is terminated with `\r\n`. 3 | } 4 | -------------------------------------------------------------------------------- /tests/json5_examples/todo/unicode-unquoted-key.json5: -------------------------------------------------------------------------------- 1 | { 2 | ümlåût: "that's not really an ümlaüt, but this is" 3 | } -------------------------------------------------------------------------------- /tests/json5_examples/comments/top-level-inline-comment.txt: -------------------------------------------------------------------------------- 1 | // This should fail; comments cannot be the only top-level value. -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_number_very_big_negative_int.json: -------------------------------------------------------------------------------- 1 | [-237462374673276894279832749832423479823246327846] -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/fail01_EXCLUDE.json: -------------------------------------------------------------------------------- 1 | "A JSON payload should be an object or array, not a string." -------------------------------------------------------------------------------- /tests/json5_examples/comments/block-comment-following-array-element.json5: -------------------------------------------------------------------------------- 1 | [ 2 | false 3 | /* 4 | true 5 | */ 6 | ] -------------------------------------------------------------------------------- /tests/json5_examples/new-lines/escaped-cr.json5: -------------------------------------------------------------------------------- 1 | { // the following string contains an escaped `\r` a: 'line 1 \ line 2' } -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | # Prettier friendly markdownlint config (all formatting rules disabled) 2 | extends: markdownlint/style/prettier 3 | -------------------------------------------------------------------------------- /.trunk/.gitignore: -------------------------------------------------------------------------------- 1 | *out 2 | *logs 3 | *actions 4 | *notifications 5 | *tools 6 | plugins 7 | user_trunk.yaml 8 | user.yaml 9 | tmp 10 | -------------------------------------------------------------------------------- /tests/json5_examples/comments/inline-comment-following-top-level-value.json5: -------------------------------------------------------------------------------- 1 | null // Some non-comment top-level value is needed; we use null here. -------------------------------------------------------------------------------- /tests/json5_examples/comments/top-level-block-comment.txt: -------------------------------------------------------------------------------- 1 | /* 2 | This should fail; 3 | comments cannot be the only top-level value. 4 | */ -------------------------------------------------------------------------------- /tests/json5_examples/comments/inline-comment-preceding-top-level-value.json5: -------------------------------------------------------------------------------- 1 | // Some non-comment top-level value is needed; we use null below. 2 | null -------------------------------------------------------------------------------- /tests/json5_examples/new-lines/escaped-lf.json5: -------------------------------------------------------------------------------- 1 | { 2 | // the following string contains an escaped `\n` 3 | a: 'line 1 \ 4 | line 2' 5 | } 6 | -------------------------------------------------------------------------------- /tests/json5_examples/new-lines/escaped-crlf.json5: -------------------------------------------------------------------------------- 1 | { 2 | // the following string contains an escaped `\r\n` 3 | a: 'line 1 \ 4 | line 2' 5 | } 6 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_number_double_close_to_zero.json: -------------------------------------------------------------------------------- 1 | [-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] 2 | -------------------------------------------------------------------------------- /tests/json5_examples/comments/top-level-block-comment.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 77, 3 | lineNumber: 4, 4 | columnNumber: 3, 5 | message: "Unexpected EOF" 6 | } -------------------------------------------------------------------------------- /tests/json5_examples/strings/unescaped-multi-line-string.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 5, 3 | lineNumber: 2, 4 | columnNumber: 0, 5 | message: "Bad string" 6 | } -------------------------------------------------------------------------------- /tests/json5_examples/arrays/no-comma-array.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 16, 3 | lineNumber: 3, 4 | columnNumber: 5, 5 | message: "Expected ']' instead of 'f'" 6 | } -------------------------------------------------------------------------------- /tests/json5_examples/comments/block-comment-following-top-level-value.json5: -------------------------------------------------------------------------------- 1 | null 2 | /* 3 | Some non-comment top-level value is needed; 4 | we use null above. 5 | */ -------------------------------------------------------------------------------- /tests/json5_examples/comments/block-comment-preceding-top-level-value.json5: -------------------------------------------------------------------------------- 1 | /* 2 | Some non-comment top-level value is needed; 3 | we use null below. 4 | */ 5 | null -------------------------------------------------------------------------------- /tests/json5_examples/comments/top-level-inline-comment.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 66, 3 | lineNumber: 1, 4 | columnNumber: 67, 5 | message: "Unexpected EOF" 6 | } -------------------------------------------------------------------------------- /tests/json5_examples/strings/no-comma-array.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 16, 3 | lineNumber: 3, 4 | columNumber: 5, 5 | message: "Expected ']' instead of 'f'" 6 | } -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_iso_latin_1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_iso_latin_1.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_invalid_utf8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_array_invalid_utf8.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object_long_strings.json: -------------------------------------------------------------------------------- 1 | {"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/y_object_string_unicode.json: -------------------------------------------------------------------------------- 1 | {"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_invalid_utf-8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_invalid_utf-8.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_utf16BE_no_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_utf16BE_no_BOM.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_utf16LE_no_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_utf16LE_no_BOM.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_array_a_invalid_utf8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_array_a_invalid_utf8.json -------------------------------------------------------------------------------- /tests/json5_examples/new-lines/.gitattributes: -------------------------------------------------------------------------------- 1 | # Since we're testing different representations of new lines, 2 | # treat all tests in this folder as binary files. 3 | 4 | * binary 5 | -------------------------------------------------------------------------------- /tests/json5_examples/objects/leading-comma-object.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 7, 3 | lineNumber: 2, 4 | columnNumber: 5, 5 | message: "Bad identifier as unquoted key" 6 | } -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_UTF-16LE_with_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_UTF-16LE_with_BOM.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_truncated-utf-8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_truncated-utf-8.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_single_eacute.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_structure_single_eacute.json -------------------------------------------------------------------------------- /tests/json5_examples/objects/illegal-unquoted-key-number.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 7, 3 | lineNumber: 2, 4 | columnNumber: 5, 5 | message: "Bad identifier as unquoted key" 6 | } -------------------------------------------------------------------------------- /tests/json5_examples/objects/illegal-unquoted-key-symbol.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 12, 3 | lineNumber: 2, 4 | columnNumber: 10, 5 | message: "Expected ':' instead of '-'" 6 | } -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/string_1_invalid_codepoint.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_transform/string_1_invalid_codepoint.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_UTF-8_invalid_sequence.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_UTF-8_invalid_sequence.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_UTF8_surrogate_U+D800.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_UTF8_surrogate_U+D800.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_not_in_unicode_range.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_not_in_unicode_range.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_invalid-utf-8-in-int.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_number_invalid-utf-8-in-int.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_incomplete_UTF8_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_structure_incomplete_UTF8_BOM.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_structure_lone-invalid-utf-8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_structure_lone-invalid-utf-8.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/string_2_invalid_codepoints.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_transform/string_2_invalid_codepoints.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/string_3_invalid_codepoints.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_transform/string_3_invalid_codepoints.json -------------------------------------------------------------------------------- /.yamllint.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | quoted-strings: 3 | required: only-when-needed 4 | extra-allowed: ["{|}"] 5 | key-duplicates: {} 6 | octal-values: 7 | forbid-implicit-octal: true 8 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_number_huge_exp.json: -------------------------------------------------------------------------------- 1 | [0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_invalid-utf-8-in-escape.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_string_invalid-utf-8-in-escape.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_lone_utf8_continuation_byte.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_lone_utf8_continuation_byte.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_overlong_sequence_2_bytes.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_overlong_sequence_2_bytes.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_overlong_sequence_6_bytes.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_overlong_sequence_6_bytes.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_invalid-utf-8-in-bigger-int.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_number_invalid-utf-8-in-bigger-int.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_invalid-utf-8-in-exponent.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_number_invalid-utf-8-in-exponent.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_string_invalid_utf8_after_escape.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_string_invalid_utf8_after_escape.json -------------------------------------------------------------------------------- /tests/json5_examples/misc/valid-whitespace.json5: -------------------------------------------------------------------------------- 1 | { 2 | // An invalid form feed character (\x0c) has been entered before this comment. 3 | // Be careful not to delete it. 4 | "a": true 5 | } 6 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_string_overlong_sequence_6_bytes_null.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/i_string_overlong_sequence_6_bytes_null.json -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_number_real_with_invalid_utf8_after_e.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_number_real_with_invalid_utf8_after_e.json -------------------------------------------------------------------------------- /ruff.toml: -------------------------------------------------------------------------------- 1 | # Generic, formatter-friendly config. 2 | lint.select = ["B", "D3", "E", "F"] 3 | 4 | # Never enforce `E501` (line length violations). This should be handled by formatters. 5 | lint.ignore = ["E501"] 6 | -------------------------------------------------------------------------------- /tests/json5_examples/comments/unterminated-block-comment.txt: -------------------------------------------------------------------------------- 1 | true 2 | /* 3 | This block comment doesn't terminate. 4 | There was a legitimate value before this, 5 | but this is still invalid JS/JSON5. 6 | -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/pass03.json: -------------------------------------------------------------------------------- 1 | { 2 | "JSON Test Pattern pass3": { 3 | "The outermost value": "must be an object or array.", 4 | "In this test": "It is an object." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/json5_examples/objects/unquoted-keys.json5: -------------------------------------------------------------------------------- 1 | { 2 | hello: "world", 3 | _: "underscore", 4 | $: "dollar sign", 5 | one1: "numerals", 6 | _$_: "multiple symbols", 7 | $_$hello123world_$_: "mixed" 8 | } -------------------------------------------------------------------------------- /docs/api_reference/core.md: -------------------------------------------------------------------------------- 1 | # Core 2 | 3 | ::: ujson5.decoder 4 | options: 5 | members: 6 | - JsonValue 7 | - JSON5DecodeError 8 | - JSON5EncodeError 9 | relative_crossrefs: true 10 | -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/readme.txt: -------------------------------------------------------------------------------- 1 | Test suite from http://json.org/JSON_checker/. 2 | 3 | If the JSON_checker is working correctly, it must accept all of the pass*.json files and reject all of the fail*.json files. 4 | -------------------------------------------------------------------------------- /tests/json5_examples/comments/block-comment-with-asterisks.json5: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a JavaDoc-like block comment. 3 | * It contains asterisks inside of it. 4 | * It might also be closed with multiple asterisks. 5 | * Like this: 6 | **/ 7 | true -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/n_object_lone_continuation_byte_in_key_and_trailing_comma.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austinyu/ujson5/HEAD/tests/json_test_suite/test_parsing/n_object_lone_continuation_byte_in_key_and_trailing_comma.json -------------------------------------------------------------------------------- /tests/test_version.py: -------------------------------------------------------------------------------- 1 | """Test the version of the package.""" 2 | 3 | import importlib 4 | 5 | import ujson5 6 | 7 | 8 | def test_version_consistency(): 9 | """Test that the version in the package is consistent with the version in the metadata.""" 10 | assert ujson5.__version__ == importlib.metadata.version("ujson5") 11 | -------------------------------------------------------------------------------- /tests/json5_examples/new-lines/.editorconfig: -------------------------------------------------------------------------------- 1 | # Since we're testing different representations of new lines, 2 | # make sure the editor doesn't mangle line endings. 3 | # Don't commit files in this directory unless you've checked 4 | # their escaped new lines. 5 | 6 | [*-lf.*] 7 | end_of_line = lf 8 | 9 | [*-cr.*] 10 | end_of_line = cr 11 | 12 | [*-crlf.*] 13 | end_of_line = crlf 14 | -------------------------------------------------------------------------------- /docs/api_reference/decoder.md: -------------------------------------------------------------------------------- 1 | # Decoder 2 | 3 | !!! Note 4 | Checkout the [getting started guide](../start_decoding.md) for more details on encoding. 5 | 6 | ::: ujson5.decoder 7 | options: 8 | members: 9 | - ObjectHookArg 10 | - ObjectHook 11 | - ObjectPairsHookArg 12 | - ObjectPairsHook 13 | - Json5Decoder 14 | - load 15 | - loads 16 | relative_crossrefs: true 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # pytest 7 | .cache/ 8 | 9 | # Coverage reports 10 | htmlcov/ 11 | .tox/ 12 | .coverage 13 | .coverage.* 14 | .cache 15 | nosetests.xml 16 | coverage.xml 17 | *.cover 18 | .hypothesis/ 19 | .pytest_cache/ 20 | 21 | # Built wheels 22 | *.whl 23 | dist/* 24 | 25 | site/* 26 | 27 | .venv/* 28 | .benchmarks/* 29 | .codspeed/* 30 | 31 | _version.py 32 | -------------------------------------------------------------------------------- /tests/test_blns.py: -------------------------------------------------------------------------------- 1 | """Test big list of naughty strings. 2 | from https://github.com/minimaxir/big-list-of-naughty-strings""" 3 | 4 | import os 5 | from pathlib import Path 6 | 7 | import ujson5 8 | 9 | BLNS_PATH = Path(os.path.dirname(__file__)) / "blns" / "blns.json" 10 | 11 | 12 | def test_blns() -> None: 13 | """Test for JSON checker files.""" 14 | with open(BLNS_PATH, "r", encoding="utf-8") as file: 15 | ujson5.load(file, strict=False) 16 | -------------------------------------------------------------------------------- /docs/api_reference/encoder.md: -------------------------------------------------------------------------------- 1 | # Encoder 2 | 3 | !!! Note 4 | Checkout the [getting started guide](../start_encoding.md) for more details on encoding. 5 | 6 | ::: ujson5.encoder 7 | options: 8 | members: 9 | - JSON5Encoder 10 | - dump 11 | - dumps 12 | relative_crossrefs: true 13 | 14 | 15 | ::: ujson5.encoder 16 | options: 17 | members: 18 | - DefaultInterface 19 | - Serializable 20 | - KeyQuotation 21 | 22 | relative_crossrefs: true 23 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = 3 | # whitespace before ':' 4 | E203, 5 | # line break before binary operator 6 | W503, 7 | # line too long (82 > 79 characters) 8 | E501, 9 | # Missing type annotation for self in method 10 | ANN101, 11 | # Name of the function uses load, but not uses from 12 | FNE004 13 | 14 | exclude = .venv | .trunk 15 | 16 | per-file-ignores = 17 | # print() is used in the code 18 | src/ujson5/cli.py: T201 19 | tests/test_snapshots/generate_snapshots.py: T201 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: ujson5 Feature request 2 | description: 'Suggest a new feature for ujson5' 3 | labels: [feature request] 4 | 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: Thank you for contributing to ujson5! 🎉 9 | 10 | - type: textarea 11 | id: description 12 | attributes: 13 | label: Description 14 | description: | 15 | Please give as much detail as possible about the feature you would like to suggest. 🙏 16 | 17 | validations: 18 | required: true 19 | -------------------------------------------------------------------------------- /tests/test_snapshots/snapshots/alpha_default.json5: -------------------------------------------------------------------------------- 1 | {"height": 180, "weight": 70, "age": 30, "name": "Alpha", "courses": {"CS101": 90, "ART101": 80, "HIS101": 70}, "hobbies": ["reading", "swimming", "coding"], "project": {"project_name": "Alpha's Project", "pkg_license": "MIT", "build_backend": "Poetry-core", "dependency_manager": "poetry", "static_code_checkers": ["flake8", "mypy"], "formatter": ["black", "isort"], "spell_checker": "cspell", "docs": "mkdocs", "code_editor": "vs_code", "pre_commit": true, "cloud_code_base": "github"}, "prop": {"house": "Alpha's House", "car": "Alpha's Car"}} 2 | -------------------------------------------------------------------------------- /tests/test_snapshots/snapshots/alpha_no_indent.json5: -------------------------------------------------------------------------------- 1 | {"height": 180, "weight": 70, "age": 30, "name": "Alpha", "courses": {"CS101": 90, "ART101": 80, "HIS101": 70}, "hobbies": ["reading", "swimming", "coding"], "project": {"project_name": "Alpha's Project", "pkg_license": "MIT", "build_backend": "Poetry-core", "dependency_manager": "poetry", "static_code_checkers": ["flake8", "mypy"], "formatter": ["black", "isort"], "spell_checker": "cspell", "docs": "mkdocs", "code_editor": "vs_code", "pre_commit": true, "cloud_code_base": "github"}, "prop": {"house": "Alpha's House", "car": "Alpha's Car"}} 2 | -------------------------------------------------------------------------------- /tests/json5_examples/misc/readme-example.json5: -------------------------------------------------------------------------------- 1 | { 2 | foo: 'bar', 3 | while: true, 4 | 5 | this: 'is a \ 6 | multi-line string', 7 | 8 | // this is an inline comment 9 | here: 'is another', // inline comment 10 | 11 | /* this is a block comment 12 | that continues on another line */ 13 | 14 | hex: 0xDEADbeef, 15 | half: .5, 16 | delta: +10, 17 | to: Infinity, // and beyond! 18 | 19 | finally: 'a trailing comma', 20 | oh: [ 21 | "we shouldn't forget", 22 | 'arrays can have', 23 | 'trailing commas too', 24 | ], 25 | } 26 | -------------------------------------------------------------------------------- /release/shared.py: -------------------------------------------------------------------------------- 1 | """This module contains shared variables and functions for the release scripts.""" 2 | 3 | import subprocess 4 | from pathlib import Path 5 | 6 | 7 | def run_command(*args: str) -> str: 8 | """Run a shell command and return the output.""" 9 | p = subprocess.run(args, stdout=subprocess.PIPE, check=True, encoding="utf-8") 10 | return p.stdout.strip() 11 | 12 | 13 | REPO = "austinyu/ujson5" 14 | CHANGELOG_PATH = Path(__file__).parent.parent / "CHANGELOG.md" 15 | PACKAGE_VERSION_PATH = ( 16 | Path(__file__).parent.parent / "src" / "ujson5" / "__version__.py" 17 | ) 18 | GITHUB_TOKEN = run_command("gh", "auth", "token") 19 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | # Contribution 2 | 3 | All contributions are welcome! 4 | 5 | ## Reporting issues 6 | If you find any issues or have any suggestions, please open an issue on the [GitHub issue tracker](https://github.com/austinyu/ujson5/issues). Please provide as much information as possible, including the version of `ujson5` you are using, the version of Python you are using, and the platform you are on. 7 | 8 | ## Contributing code 9 | 10 | ### Prerequisites 11 | 12 | - Any Python version above Python 3.10 13 | - [uv](https://docs.astral.sh/uv/) or other virtual environment tool 14 | - git 15 | - make 16 | 17 | ### CLIs 18 | 19 | - `mkdocs server` 20 | -------------------------------------------------------------------------------- /tests/test_benchmark.py: -------------------------------------------------------------------------------- 1 | """Benchmark tests for ujson5.""" 2 | 3 | import os 4 | 5 | import pytest 6 | 7 | import ujson5 8 | 9 | from . import example_consts 10 | 11 | 12 | @pytest.mark.parametrize( 13 | "path", 14 | example_consts.VALID_EXAMPLES, 15 | ) 16 | @pytest.mark.skipif(not os.getenv("CI_ENV"), reason="Run only in CI environment") 17 | def test_ujson5_benchmark(path: str, benchmark) -> None: 18 | """Test valid JSON5 examples.""" 19 | with open( 20 | os.path.join(example_consts.EXAMPLE_ROOT, "arrays", path), "r", encoding="utf8" 21 | ) as file: 22 | content = file.read() 23 | benchmark(ujson5.loads, content) 24 | -------------------------------------------------------------------------------- /.github/workflows/formatters.yml: -------------------------------------------------------------------------------- 1 | name: formatter 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | # Allows you to run this workflow manually from the Actions tab 9 | workflow_dispatch: 10 | 11 | permissions: 12 | contents: write 13 | 14 | jobs: 15 | lint: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Install dependencies 20 | run: | 21 | python -m pip install --upgrade pip 22 | pip install ruff 23 | pip install isort 24 | - name: Run isort 25 | run: isort 26 | - name: Run Ruff 27 | run: ruff format 28 | -------------------------------------------------------------------------------- /src/ujson5/__init__.py: -------------------------------------------------------------------------------- 1 | """JSON5 parser and serializer for Python.""" 2 | 3 | from ._version import __version__ as gen_version 4 | from .core import JSON5DecodeError, JSON5EncodeError, JsonValue, version_info 5 | from .decoder import Json5Decoder, ObjectHookArg, ObjectPairsHookArg, load, loads 6 | from .encoder import JSON5Encoder, Serializable, dump, dumps 7 | 8 | __version__ = gen_version 9 | 10 | 11 | __all__ = [ 12 | "__version__", 13 | "version_info", 14 | "JsonValue", 15 | "JSON5DecodeError", 16 | "JSON5EncodeError", 17 | "Json5Decoder", 18 | "load", 19 | "loads", 20 | "JSON5Encoder", 21 | "dumps", 22 | "dump", 23 | "ObjectPairsHookArg", 24 | "ObjectHookArg", 25 | "Serializable", 26 | ] 27 | -------------------------------------------------------------------------------- /tests/json5_examples/README.md: -------------------------------------------------------------------------------- 1 | # Parse Test Cases for JSON5 2 | 3 | The test cases' file extension signals the expected behavior: 4 | 5 | - Valid JSON should remain valid JSON5. These cases have a `.json` extension 6 | and are tested via `JSON.parse()`. 7 | 8 | - JSON5's new features should remain valid ES5. These cases have a `.json5` 9 | extension are tested via `eval()`. 10 | 11 | - Valid ES5 that's explicitly disallowed by JSON5 is also invalid JSON. These 12 | cases have a `.js` extension and are expected to fail. 13 | 14 | - Invalid ES5 should remain invalid JSON5. These cases have a `.txt` extension 15 | and are expected to fail. 16 | 17 | This should cover all our bases. Most of the cases are unit tests for each 18 | supported data type, but aggregate test cases are welcome, too. 19 | 20 | ## License 21 | 22 | MIT. See [LICENSE.md](./LICENSE.md) for details. 23 | -------------------------------------------------------------------------------- /tests/example_consts.py: -------------------------------------------------------------------------------- 1 | """constants related to examples from the official JSON5 test suite.""" 2 | 3 | from os import listdir 4 | from os.path import dirname, join 5 | from pathlib import Path 6 | 7 | EXAMPLE_ROOT: Path = Path(dirname(__file__)) / "json5_examples" 8 | 9 | CATEGORIES: list[str] = [ 10 | "arrays", 11 | "comments", 12 | "misc", 13 | "new-lines", 14 | "numbers", 15 | "objects", 16 | "strings", 17 | "todo", 18 | ] 19 | 20 | VALID_EXAMPLES: list[Path] = [ 21 | EXAMPLE_ROOT / cat / f 22 | for cat in CATEGORIES 23 | for f in listdir(join(EXAMPLE_ROOT, cat)) 24 | if f.endswith(".json5") or f.endswith(".json") 25 | ] 26 | 27 | INVALID_EXAMPLES: list[Path] = [ 28 | EXAMPLE_ROOT / cat / f 29 | for cat in CATEGORIES 30 | for f in listdir(join(EXAMPLE_ROOT, cat)) 31 | if f.endswith(".js") or f.endswith(".txt") 32 | ] 33 | -------------------------------------------------------------------------------- /tests/test_snapshots/snapshots/alpha_no_comments.json5: -------------------------------------------------------------------------------- 1 | { 2 | "height": 180, 3 | "weight": 70, 4 | "age": 30, 5 | "name": "Alpha", 6 | "courses": { 7 | "CS101": 90, 8 | "ART101": 80, 9 | "HIS101": 70, 10 | }, 11 | "hobbies": [ 12 | "reading", 13 | "swimming", 14 | "coding", 15 | ], 16 | "project": { 17 | "project_name": "Alpha's Project", 18 | "pkg_license": "MIT", 19 | "build_backend": "Poetry-core", 20 | "dependency_manager": "poetry", 21 | "static_code_checkers": [ 22 | "flake8", 23 | "mypy", 24 | ], 25 | "formatter": [ 26 | "black", 27 | "isort", 28 | ], 29 | "spell_checker": "cspell", 30 | "docs": "mkdocs", 31 | "code_editor": "vs_code", 32 | "pre_commit": true, 33 | "cloud_code_base": "github", 34 | }, 35 | "prop": { 36 | "house": "Alpha's House", 37 | "car": "Alpha's Car", 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /tests/test_snapshots/snapshots/alpha_no_trailing_comma.json5: -------------------------------------------------------------------------------- 1 | { 2 | "height": 180, 3 | "weight": 70, 4 | "age": 30, 5 | "name": "Alpha", 6 | "courses": { 7 | "CS101": 90, 8 | "ART101": 80, 9 | "HIS101": 70 10 | }, 11 | "hobbies": [ 12 | "reading", 13 | "swimming", 14 | "coding" 15 | ], 16 | "project": { 17 | "project_name": "Alpha's Project", 18 | "pkg_license": "MIT", 19 | "build_backend": "Poetry-core", 20 | "dependency_manager": "poetry", 21 | "static_code_checkers": [ 22 | "flake8", 23 | "mypy" 24 | ], 25 | "formatter": [ 26 | "black", 27 | "isort" 28 | ], 29 | "spell_checker": "cspell", 30 | "docs": "mkdocs", 31 | "code_editor": "vs_code", 32 | "pre_commit": true, 33 | "cloud_code_base": "github" 34 | }, 35 | "prop": { 36 | "house": "Alpha's House", 37 | "car": "Alpha's Car" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/test_snapshots/snapshots/alpha_special_separators.json5: -------------------------------------------------------------------------------- 1 | { 2 | "height"->180| 3 | "weight"->70| 4 | "age"->30| 5 | "name"->"Alpha"| 6 | "courses"->{ 7 | "CS101"->90| 8 | "ART101"->80| 9 | "HIS101"->70| 10 | }| 11 | "hobbies"->[ 12 | "reading"| 13 | "swimming"| 14 | "coding"| 15 | ]| 16 | "project"->{ 17 | "project_name"->"Alpha's Project"| 18 | "pkg_license"->"MIT"| 19 | "build_backend"->"Poetry-core"| 20 | "dependency_manager"->"poetry"| 21 | "static_code_checkers"->[ 22 | "flake8"| 23 | "mypy"| 24 | ]| 25 | "formatter"->[ 26 | "black"| 27 | "isort"| 28 | ]| 29 | "spell_checker"->"cspell"| 30 | "docs"->"mkdocs"| 31 | "code_editor"->"vs_code"| 32 | "pre_commit"->true| 33 | "cloud_code_base"->"github"| 34 | }| 35 | "prop"->{ 36 | "house"->"Alpha's House"| 37 | "car"->"Alpha's Car"| 38 | }| 39 | } 40 | -------------------------------------------------------------------------------- /tests/test_snapshots/snapshots/alpha_with_trailing_comma.json5: -------------------------------------------------------------------------------- 1 | { 2 | "height": 180, 3 | "weight": 70, 4 | "age": 30, 5 | "name": "Alpha", 6 | "courses": { 7 | "CS101": 90, 8 | "ART101": 80, 9 | "HIS101": 70, 10 | }, 11 | "hobbies": [ 12 | "reading", 13 | "swimming", 14 | "coding", 15 | ], 16 | "project": { 17 | "project_name": "Alpha's Project", 18 | "pkg_license": "MIT", 19 | "build_backend": "Poetry-core", 20 | "dependency_manager": "poetry", 21 | "static_code_checkers": [ 22 | "flake8", 23 | "mypy", 24 | ], 25 | "formatter": [ 26 | "black", 27 | "isort", 28 | ], 29 | "spell_checker": "cspell", 30 | "docs": "mkdocs", 31 | "code_editor": "vs_code", 32 | "pre_commit": true, 33 | "cloud_code_base": "github", 34 | }, 35 | "prop": { 36 | "house": "Alpha's House", 37 | "car": "Alpha's Car", 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_parsing/i_structure_500_nested_arrays.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /tests/test_unit_tests/test_comment_lexer.py: -------------------------------------------------------------------------------- 1 | """Tests for comment lexer.""" 2 | 3 | import pytest 4 | 5 | from ujson5.lexer import validate_comment 6 | 7 | 8 | @pytest.mark.parametrize( 9 | "comment,end", 10 | [ 11 | ("//", 2), 12 | ("// some comment is here\n new line", 24), 13 | ("/* some comment is here */", 26), 14 | ("/* some comment is here\n new line */", 36), 15 | ("/* some comment is here\n new line */ new line", 36), 16 | ], 17 | ) 18 | def test_valid_comments(comment: str, end: int) -> None: 19 | """Test valid comments.""" 20 | idx = validate_comment(comment, 0) 21 | assert idx == end 22 | 23 | 24 | @pytest.mark.parametrize( 25 | "comment", 26 | [ 27 | "/", 28 | "/*", 29 | "/* some comment is here", 30 | "/* some comment is here*", 31 | ], 32 | ) 33 | def test_invalid_comments(comment: str) -> None: 34 | """Test invalid comments.""" 35 | with pytest.raises(ValueError): 36 | validate_comment(comment, 0) 37 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: build docs 3 | 4 | on: 5 | push: 6 | branches: [main] 7 | pull_request: 8 | branches: [main] 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | permissions: 13 | contents: write 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Install uv 21 | uses: astral-sh/setup-uv@v5 22 | - name: Set up Python 23 | uses: actions/setup-python@v5 24 | with: 25 | python-version-file: pyproject.toml 26 | - name: Install dependencies 27 | run: | 28 | uv venv 29 | uv pip install --upgrade pip 30 | uv sync --group docs 31 | - name: Build docs 32 | run: | 33 | uv run mkdocs build 34 | 35 | - name: Upload docs to artifact 36 | uses: actions/upload-artifact@v4 37 | with: 38 | name: docs 39 | path: site/ 40 | -------------------------------------------------------------------------------- /.github/workflows/mypy.yml: -------------------------------------------------------------------------------- 1 | name: mypy type check 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | # Allows you to run this workflow manually from the Actions tab 9 | workflow_dispatch: 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | flake8-lint: 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ["3.10", "3.11", "3.12", "3.13"] 20 | runs-on: ubuntu-latest 21 | name: mypy 22 | steps: 23 | - name: Check out repository 24 | uses: actions/checkout@v4 25 | - name: Set up Python ${{ matrix.python-version }} 26 | uses: actions/setup-python@v5 27 | with: 28 | python-version: ${{ matrix.python-version }} 29 | 30 | - name: Install dependencies 31 | run: | 32 | python -m pip install --upgrade pip 33 | pip install mypy 34 | pip install pytest 35 | pip install build 36 | python -m build 37 | 38 | - name: mypy type check 39 | run: | 40 | mypy src tests 41 | -------------------------------------------------------------------------------- /ujson5.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "cSpell.words": [], 9 | "python.defaultInterpreterPath": "${workspaceFolder}/.venv/Scripts/python.exe", 10 | "pylint.interpreter": [ 11 | "${workspaceFolder}/.venv/Scripts/python.exe" 12 | ], 13 | "editor.rulers": [ 14 | 95 15 | ], 16 | "yaml.schemas": { 17 | "https://squidfunk.github.io/mkdocs-material/schema.json": "mkdocs.yml" 18 | }, 19 | "yaml.customTags": [ 20 | "!ENV scalar", 21 | "!ENV sequence", 22 | "!relative scalar", 23 | "tag:yaml.org,2002:python/name:material.extensions.emoji.to_svg", 24 | "tag:yaml.org,2002:python/name:material.extensions.emoji.twemoji", 25 | "tag:yaml.org,2002:python/name:pymdownx.superfences.fence_code_format", 26 | "tag:yaml.org,2002:python/object/apply:pymdownx.slugs.slugify mapping" 27 | ], 28 | "pylint.path": [ 29 | "${workspaceFolder}\\tests" 30 | ], 31 | "mypy-type-checker.importStrategy": "fromEnvironment", 32 | "mypy-type-checker.interpreter": [ 33 | "${workspaceFolder}/.venv/Scripts/python.exe" 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/benchmark.yml: -------------------------------------------------------------------------------- 1 | name: benchmark 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | # push: 8 | # branches: ["main"] 9 | # pull_request: 10 | # branches: ["main"] 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | benchmarks: 16 | name: Run benchmarks 17 | runs-on: ubuntu-latest 18 | strategy: 19 | matrix: 20 | shard: [1, 2, 3, 4, 5] 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Install uv 24 | uses: astral-sh/setup-uv@v5 25 | - name: Set up Python 26 | uses: actions/setup-python@v5 27 | with: 28 | python-version-file: pyproject.toml 29 | - name: Install dependencies 30 | run: | 31 | uv pip install --upgrade pip 32 | uv sync 33 | 34 | - name: Run benchmarks 35 | uses: CodSpeedHQ/action@v3 36 | env: 37 | CI_ENV: true 38 | with: 39 | run: uv run pytest tests/ --codspeed --test-group=${{ matrix.shard }} --test-group-count=5 40 | token: ${{ secrets.CODSPEED_TOKEN }} 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Sir Austin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/flake8.yml: -------------------------------------------------------------------------------- 1 | name: flake8 lint 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | # Allows you to run this workflow manually from the Actions tab 9 | workflow_dispatch: 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | flake8-lint: 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ["3.10", "3.11", "3.12", "3.13"] 20 | runs-on: ubuntu-latest 21 | name: flake8 22 | steps: 23 | - name: Check out repository 24 | uses: actions/checkout@v4 25 | - name: Set up Python ${{ matrix.python-version }} 26 | uses: actions/setup-python@v5 27 | with: 28 | python-version: ${{ matrix.python-version }} 29 | 30 | - name: Install uv 31 | uses: astral-sh/setup-uv@v5 32 | with: 33 | python-version: ${{ matrix.python-version }} 34 | - name: Install dependencies 35 | run: | 36 | uv venv 37 | uv pip install --upgrade pip 38 | uv sync --group static_checkers 39 | - name: Run flake8 40 | run: | 41 | uv run flake8 src tests 42 | -------------------------------------------------------------------------------- /tests/json5_examples/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2016 Aseem Kishore, and [others](https://github.com/json5/json5/contributors). 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/test_snapshots/snapshots/alpha_7_indent.json5: -------------------------------------------------------------------------------- 1 | { 2 | "height": 180, 3 | "weight": 70, 4 | "age": 30, 5 | "name": "Alpha", 6 | "courses": { 7 | "CS101": 90, 8 | "ART101": 80, 9 | "HIS101": 70, 10 | }, 11 | "hobbies": [ 12 | "reading", 13 | "swimming", 14 | "coding", 15 | ], 16 | "project": { 17 | "project_name": "Alpha's Project", 18 | "pkg_license": "MIT", 19 | "build_backend": "Poetry-core", 20 | "dependency_manager": "poetry", 21 | "static_code_checkers": [ 22 | "flake8", 23 | "mypy", 24 | ], 25 | "formatter": [ 26 | "black", 27 | "isort", 28 | ], 29 | "spell_checker": "cspell", 30 | "docs": "mkdocs", 31 | "code_editor": "vs_code", 32 | "pre_commit": true, 33 | "cloud_code_base": "github", 34 | }, 35 | "prop": { 36 | "house": "Alpha's House", 37 | "car": "Alpha's Car", 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /.trunk/trunk.yaml: -------------------------------------------------------------------------------- 1 | # This file controls the behavior of Trunk: https://docs.trunk.io/cli 2 | # To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml 3 | version: 0.1 4 | cli: 5 | version: 1.22.11 6 | # Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins) 7 | plugins: 8 | sources: 9 | - id: trunk 10 | ref: v1.6.7 11 | uri: https://github.com/trunk-io/plugins 12 | # Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes) 13 | runtimes: 14 | enabled: 15 | - node@18.20.5 16 | - python@3.10.8 17 | # This is the section where you manage your linters. (https://docs.trunk.io/check/configuration) 18 | lint: 19 | enabled: 20 | - actionlint@1.7.7 21 | - bandit@1.8.3 22 | - black@25.1.0 23 | - checkov@3.2.386 24 | - flake8@7.1.2 25 | - git-diff-check 26 | - isort@6.0.1 27 | - markdownlint@0.44.0 28 | - prettier@3.5.3 29 | - pylint@3.3.5 30 | - ruff@0.10.0 31 | - taplo@0.9.3 32 | - trufflehog@3.88.17 33 | - yamllint@1.36.0 34 | actions: 35 | disabled: 36 | - trunk-announce 37 | - trunk-check-pre-push 38 | - trunk-fmt-pre-commit 39 | enabled: 40 | - trunk-upgrade-available 41 | -------------------------------------------------------------------------------- /cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2", 3 | "ignorePaths": [ 4 | ".github/*", 5 | ".pre-commit-config.yaml", 6 | "tests/native_json_benchmark/*", 7 | "tests/json_test_suite/*", 8 | "tests/blns/*", 9 | "tests/json5_examples/*", 10 | "ujson5.code-workspace", 11 | "mkdocs.yml", 12 | "Makefile" 13 | ], 14 | "dictionaryDefinitions": [], 15 | "dictionaries": [], 16 | "words": [ 17 | "addopts", 18 | "austinyu", 19 | "bfnrtv", 20 | "blns", 21 | "Characterbut", 22 | "Charactersopt", 23 | "citm", 24 | "codespell", 25 | "codspeed", 26 | "crossrefs", 27 | "docstrings", 28 | "elif", 29 | "fnames", 30 | "fstring", 31 | "htmlcov", 32 | "imag", 33 | "infile", 34 | "isinstance", 35 | "isort", 36 | "isspace", 37 | "jsonchecker", 38 | "mkdocs", 39 | "mkdocstrings", 40 | "mypy", 41 | "nativejson", 42 | "NOINT", 43 | "nosetests", 44 | "pipx", 45 | "pycache", 46 | "pyjp", 47 | "pylint", 48 | "pymdown", 49 | "pypi", 50 | "pytest", 51 | "Pythonic", 52 | "sdist", 53 | "snok", 54 | "ujson", 55 | "venv", 56 | "virtualenvs", 57 | "ZWNJ" 58 | ], 59 | "ignoreWords": [], 60 | "import": [] 61 | } 62 | -------------------------------------------------------------------------------- /tests/test_json_test_suit.py: -------------------------------------------------------------------------------- 1 | """Test for JSON test suite. 2 | https://github.com/nst/JSONTestSuite 3 | """ 4 | 5 | import os 6 | from pathlib import Path 7 | 8 | import pytest 9 | 10 | import ujson5 11 | 12 | BASE_FOLDER = Path(os.path.dirname(__file__)) / "json_test_suite" 13 | PARSING_FOLDER = BASE_FOLDER / "test_parsing" 14 | TRANSFORM_FOLDER = BASE_FOLDER / "test_transform" 15 | 16 | PARSING_FNAMES: list[Path] = [ 17 | f 18 | for f in PARSING_FOLDER.iterdir() 19 | if f.is_file() 20 | if f.name 21 | not in { 22 | # https://262.ecma-international.org/5.1/#sec-7.3 23 | # line separators should not be allowed in a JSON string 24 | # not sure why the test suite has them 25 | "y_string_u+2029_par_sep.json", 26 | "y_string_u+2028_line_sep.json", 27 | } 28 | ] 29 | ACCEPTED_PATHS: list[Path] = [f for f in PARSING_FNAMES if f.name.startswith("y_")] 30 | REJECTED_PATHS: list[Path] = [f for f in PARSING_FNAMES if f.name.startswith("n_")] 31 | AMBIGUOUS_PATHS: list[Path] = [f for f in PARSING_FNAMES if f.name.startswith("i_")] 32 | 33 | 34 | @pytest.mark.parametrize("file_path", ACCEPTED_PATHS) 35 | def test_accepted_json(file_path: Path) -> None: 36 | """Any accepted JSON is a valid JSON5.""" 37 | with open(file_path, "r", encoding="utf8") as file: 38 | ujson5.load(file, strict=False) 39 | -------------------------------------------------------------------------------- /.github/workflows/pylint.yml: -------------------------------------------------------------------------------- 1 | name: pylint lint 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | # Allows you to run this workflow manually from the Actions tab 9 | workflow_dispatch: 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | flake8-lint: 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ["3.10", "3.11", "3.12", "3.13"] 20 | runs-on: ubuntu-latest 21 | name: pylint 22 | steps: 23 | #---------------------------------------------- 24 | # check-out repo and set-up python 25 | #---------------------------------------------- 26 | - name: Check out repository 27 | uses: actions/checkout@v4 28 | - name: Set up Python ${{ matrix.python-version }} 29 | uses: actions/setup-python@v5 30 | with: 31 | python-version: ${{ matrix.python-version }} 32 | - name: Install dependencies 33 | run: | 34 | python -m pip install --upgrade pip 35 | pip install pylint 36 | pip install build 37 | python -m build 38 | #---------------------------------------------- 39 | # ----- pylint lint ----- 40 | #---------------------------------------------- 41 | - name: Lint code with pylint 42 | run: | 43 | pylint src tests --rcfile=.pylintrc 44 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## v1.0.1 (2025-03-19) 4 | 5 | [GitHub release](https://github.com/austinyu/ujson5/releases/tag/v1.0.1) 6 | 7 | ### What's Changed 8 | 9 | - Makefile automation by @austinyu in [#13](https://github.com/austinyu/ujson5/pull/13) 10 | - Fixed incorrect comments extraction by @austinyu in [#18](https://github.com/austinyu/ujson5/pull/18) 11 | - Trunk quality compliance by @austinyu in [#19](https://github.com/austinyu/ujson5/pull/19) 12 | - Release pipeline done by @austinyu in [#21](https://github.com/austinyu/ujson5/pull/21) 13 | 14 | [**Full Changelog**](https://github.com/austinyu/ujson5/compare/v1.0.0b...v1.0.1) 15 | 16 | ## v1.0.0a (2025-03-07) 17 | 18 | [GitHub release](https://github.com/austinyu/ujson5/releases/tag/v1.0.0a) 19 | 20 | ### What's Changed 21 | 22 | - Fixed wrong wheel name generated by shallow clone repo in CI by @austinyu in https://github.com/austinyu/ujson5/pull/7 23 | - Migrating to uv and hatch as project management tool and build tool. by @austinyu in https://github.com/austinyu/ujson5/pull/8 24 | - Improve on package metadata by @austinyu in https://github.com/austinyu/ujson5/pull/10 25 | 26 | ### New Contributors 27 | 28 | - @austinyu made their first contribution in https://github.com/austinyu/ujson5/pull/7 29 | 30 | [**Full Changelog**](https://github.com/austinyu/ujson5/compare/v1.0.0...v1.0.0a) 31 | 32 | 33 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | # A comma-separated list of package or module names from where C extensions may be loaded. 3 | extension-pkg-whitelist= 4 | # List of modules to be ignored (as a comma-separated string) 5 | ignored-modules=pytest 6 | 7 | source-roots= 8 | src/ujson5 9 | tests 10 | 11 | ignore= 12 | _version.py, # version file 13 | 14 | [MESSAGES CONTROL] 15 | # Disable the following messages: 16 | disable= 17 | R0912, # too-many-branches 18 | R0915, # too-many-statements 19 | R0903, # too-few-public-methods 20 | R0914, # too-many-locals 21 | R0913, # too-many-arguments 22 | R0902, # too-many-instance-attributes 23 | E0401, # unable to import 24 | E0611, # no name in module 25 | 26 | [REPORTS] 27 | # Tells whether to display a full report or only the messages. 28 | reports=no 29 | score=yes 30 | 31 | [FORMAT] 32 | # Maximum number of characters on a single line. 33 | max-line-length=95 34 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 35 | # tab). 36 | indent-string=' ' 37 | 38 | [DESIGN] 39 | 40 | [SIMILARITIES] 41 | 42 | # Minimum lines number of a similarity. 43 | min-similarity-lines=6 44 | 45 | # Ignore comments when computing similarities. 46 | ignore-comments=yes 47 | 48 | # Ignore docstrings when computing similarities. 49 | ignore-docstrings=yes 50 | 51 | # Ignore imports when computing similarities. 52 | ignore-imports=yes 53 | 54 | # Signatures are removed from the similarity computation 55 | ignore-signatures=yes 56 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Report a bug or unexpected behavior in ujson5 3 | labels: [bug] 4 | 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: Thank you for contributing to ujson5! 9 | 10 | - type: textarea 11 | id: description 12 | attributes: 13 | label: Description 14 | description: | 15 | Please explain what you're seeing and what you would expect to see. 16 | 17 | Please provide as much detail as possible to make understanding and solving your problem as quick as possible. 🙏 18 | validations: 19 | required: true 20 | 21 | - type: textarea 22 | id: example 23 | attributes: 24 | label: Example Code 25 | description: > 26 | If applicable, please add a self-contained, 27 | [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) 28 | demonstrating the bug. 29 | 30 | placeholder: | 31 | import ujson5 32 | 33 | ... 34 | render: Python 35 | 36 | - type: textarea 37 | id: version 38 | attributes: 39 | label: Python, ujson5 & OS Version 40 | description: | 41 | Which version of Python & ujson5 are you using, and which Operating System? 42 | 43 | Please run the following command and copy the output below: 44 | 45 | ```bash 46 | python -c "import ujson5; print(ujson5.version_info())" 47 | ``` 48 | render: Text 49 | validations: 50 | required: true 51 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # .DEFAULT_GOAL := all 2 | sources = src tests 3 | 4 | .PHONY: .uv ## Check that uv is installed 5 | .uv: 6 | @uv -V || echo 'Please install uv: https://docs.astral.sh/uv/getting-started/installation/' 7 | 8 | .PHONY: .pre-commit ## Check that pre-commit is installed 9 | .pre-commit: .uv 10 | @uv run pre-commit -V || uv pip install pre-commit 11 | 12 | .PHONY: install ## Install the package, dependencies, and pre-commit for local development 13 | install: .uv 14 | uv sync --frozen --group all --all-extras 15 | uv pip install pre-commit 16 | uv run pre-commit install --install-hooks 17 | 18 | .PHONY: rebuild-lockfiles ## Rebuild lockfiles from scratch, updating all dependencies 19 | rebuild-lockfiles: .uv 20 | uv lock --upgrade 21 | 22 | .PHONY: format ## Auto-format python source files 23 | format: .uv 24 | uv run pre-commit run trailing-whitespace 25 | uv run pre-commit run end-of-file-fixer 26 | uv run black $(sources) 27 | 28 | .PHONY: lint ## Lint python source files 29 | lint: .uv 30 | uv run flake8 $(sources) 31 | uv run pylint $(sources) 32 | 33 | .PHONY: cspell ## Use cspell to do spellchecking 34 | cspell: .pre-commit 35 | uv run pre-commit run cspell 36 | 37 | .PHONY: typecheck ## Perform type-checking 38 | typecheck: .uv 39 | uv run mypy $(sources) 40 | 41 | .PHONY: test ## Run all tests, skipping the type-checker integration tests 42 | test: .uv 43 | uv run pytest 44 | 45 | .PHONY: all ## Run the standard set of checks performed in CI 46 | all: format lint typecheck cspell test 47 | 48 | .PHONY: docs ## Generate the docs 49 | docs: 50 | uv run mkdocs build --strict 51 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | release: 5 | types: [published] 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: write 10 | id-token: write 11 | 12 | jobs: 13 | release-build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 # Fetch all history for all tags and branches 20 | 21 | - uses: actions/setup-python@v5 22 | with: 23 | python-version: 3.x 24 | 25 | - name: Build release distributions 26 | run: | 27 | python -m pip install build 28 | python -m build 29 | 30 | - name: Upload distributions 31 | uses: actions/upload-artifact@v4 32 | with: 33 | name: release-dists 34 | path: dist/ 35 | 36 | pypi-publish: 37 | runs-on: ubuntu-latest 38 | needs: 39 | - release-build 40 | 41 | # Dedicated environments with protections for publishing are strongly recommended. 42 | # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules 43 | environment: 44 | name: pypi 45 | url: https://pypi.org/project/ujson5/ 46 | 47 | steps: 48 | - name: Retrieve release distributions 49 | uses: actions/download-artifact@v4 50 | with: 51 | name: release-dists 52 | path: dist/ 53 | 54 | - name: Publish release distributions to PyPI 55 | uses: pypa/gh-action-pypi-publish@release/v1 56 | with: 57 | packages-dir: dist/ 58 | -------------------------------------------------------------------------------- /tests/native_json_benchmark/jsonchecker/pass01.json: -------------------------------------------------------------------------------- 1 | [ 2 | "JSON Test Pattern pass1", 3 | {"object with 1 member":["array with 1 element"]}, 4 | {}, 5 | [], 6 | -42, 7 | true, 8 | false, 9 | null, 10 | { 11 | "integer": 1234567890, 12 | "real": -9876.543210, 13 | "e": 0.123456789e-12, 14 | "E": 1.234567890E+34, 15 | "": 23456789012E66, 16 | "zero": 0, 17 | "one": 1, 18 | "space": " ", 19 | "quote": "\"", 20 | "backslash": "\\", 21 | "controls": "\b\f\n\r\t", 22 | "slash": "/ & \/", 23 | "alpha": "abcdefghijklmnopqrstuvwyz", 24 | "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", 25 | "digit": "0123456789", 26 | "0123456789": "digit", 27 | "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", 28 | "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", 29 | "true": true, 30 | "false": false, 31 | "null": null, 32 | "array":[ ], 33 | "object":{ }, 34 | "address": "50 St. James Street", 35 | "url": "http://www.JSON.org/", 36 | "comment": "// /* */": " ", 38 | " s p a c e d " :[1,2 , 3 39 | 40 | , 41 | 42 | 4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], 43 | "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", 44 | "quotes": "" \u0022 %22 0x22 034 "", 45 | "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" 46 | : "A key can be any string" 47 | }, 48 | 0.5 ,98.6 49 | , 50 | 99.44 51 | , 52 | 53 | 1066, 54 | 1e1, 55 | 0.1e1, 56 | 1e-1, 57 | 1e00,2e+00,2e-00 58 | ,"rosebud"] -------------------------------------------------------------------------------- /.github/workflows/deploy_docs.yml: -------------------------------------------------------------------------------- 1 | name: build & deploy docs 2 | 3 | on: 4 | # Allows you to run this workflow manually from the Actions tab 5 | workflow_dispatch: 6 | 7 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 8 | permissions: 9 | contents: write 10 | pages: write 11 | id-token: write 12 | 13 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 14 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 15 | concurrency: 16 | group: pages 17 | cancel-in-progress: false 18 | 19 | jobs: 20 | build-deploy: 21 | runs-on: ubuntu-latest 22 | environment: 23 | name: github-pages 24 | url: ${{ steps.deployment.outputs.page_url }} 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Install uv 28 | uses: astral-sh/setup-uv@v5 29 | - name: Set up Python 30 | uses: actions/setup-python@v5 31 | with: 32 | python-version-file: pyproject.toml 33 | - name: Install dependencies 34 | run: | 35 | uv venv 36 | uv pip install --upgrade pip 37 | uv sync --group docs 38 | - name: Build docs 39 | run: | 40 | uv run mkdocs build 41 | 42 | - name: Upload docs to artifact 43 | uses: actions/upload-artifact@v4 44 | with: 45 | name: docs 46 | path: site/ 47 | - name: Setup Pages 48 | uses: actions/configure-pages@v5 49 | - name: Upload artifact 50 | uses: actions/upload-pages-artifact@v3 51 | with: 52 | path: site 53 | - name: Deploy to GitHub Pages 54 | id: deployment 55 | uses: actions/deploy-pages@v4 56 | -------------------------------------------------------------------------------- /tests/json_test_suite/test_transform/README.md: -------------------------------------------------------------------------------- 1 | # JSON Parsing Test Suite 2 | A comprehensive test suite for RFC 8259 compliant JSON parsers 3 | 4 | This repository was created as an appendix to the article [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.php). 5 | 6 | **/parsers/** 7 | 8 | This directory contains several parsers and tiny wrappers to turn the parsers into JSON validators, by returning a specific value. 9 | 10 | - `0` the parser did accept the content 11 | - `1` the parser did reject the content 12 | - `>1` the process did crash 13 | - `timeout` happens after 5 seconds 14 | 15 | **/test\_parsing/** 16 | 17 | The name of these files tell if their contents should be accepted or rejected. 18 | 19 | - `y_` content must be accepted by parsers 20 | - `n_` content must be rejected by parsers 21 | - `i_` parsers are free to accept or reject content 22 | 23 | **/test\_transform/** 24 | 25 | These files contain weird structures and characters that parsers may understand differently, eg: 26 | 27 | - huge numbers 28 | - dictionaries with similar keys 29 | - NULL characters 30 | - escaped invalid strings 31 | 32 | These files were used to produce `results/transform.html`. 33 | 34 | **/run_tests.py** 35 | 36 | Run all parsers with all files: 37 | 38 | $ python3 run_tests.py 39 | 40 | Run all parsers with a specific file: 41 | 42 | $ python3 run_tests.py file.json 43 | 44 | Run specific parsers with all files: 45 | 46 | $ echo '["Python 2.7.10", "Python 3.5.2"]' > python_only.json 47 | $ python3 run_tests.py --filter=python_only.json 48 | 49 | The script writes logs in `results/logs.txt`. 50 | 51 | The script then reads `logs.txt` and generates `results/parsing.html`. 52 | 53 | **/results/** 54 | 55 | JSON Parsing Tests 56 | -------------------------------------------------------------------------------- /tests/json_test_suite/README.md: -------------------------------------------------------------------------------- 1 | > From https://github.com/nst/JSONTestSuite 2 | 3 | # JSON Parsing Test Suite 4 | A comprehensive test suite for RFC 8259 compliant JSON parsers 5 | 6 | This repository was created as an appendix to the article [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.php). 7 | 8 | **/parsers/** 9 | 10 | This directory contains several parsers and tiny wrappers to turn the parsers into JSON validators, by returning a specific value. 11 | 12 | - `0` the parser did accept the content 13 | - `1` the parser did reject the content 14 | - `>1` the process did crash 15 | - `timeout` happens after 5 seconds 16 | 17 | **/test\_parsing/** 18 | 19 | The name of these files tell if their contents should be accepted or rejected. 20 | 21 | - `y_` content must be accepted by parsers 22 | - `n_` content must be rejected by parsers 23 | - `i_` parsers are free to accept or reject content 24 | 25 | **/test\_transform/** 26 | 27 | These files contain weird structures and characters that parsers may understand differently, eg: 28 | 29 | - huge numbers 30 | - dictionaries with similar keys 31 | - NULL characters 32 | - escaped invalid strings 33 | 34 | These files were used to produce `results/transform.html`. 35 | 36 | **/run_tests.py** 37 | 38 | Run all parsers with all files: 39 | 40 | $ python3 run_tests.py 41 | 42 | Run all parsers with a specific file: 43 | 44 | $ python3 run_tests.py file.json 45 | 46 | Run specific parsers with all files: 47 | 48 | $ echo '["Python 2.7.10", "Python 3.5.2"]' > python_only.json 49 | $ python3 run_tests.py --filter=python_only.json 50 | 51 | The script writes logs in `results/logs.txt`. 52 | 53 | The script then reads `logs.txt` and generates `results/parsing.html`. 54 | 55 | **/results/** 56 | 57 | JSON Parsing Tests 58 | -------------------------------------------------------------------------------- /docs/start_decoding.md: -------------------------------------------------------------------------------- 1 | # Deserializing / Decoding 2 | 3 | `ujson5` API is similar to the standard `json` module. If you are familiar with the `json` module, you will find `ujson5` easy to use. Like the `json` module, `ujson5` provides two main functions for decoding JSON5 strings to python objects: [load][ujson5.load] and [loads][ujson5.loads]. 4 | 5 | When using [load][ujson5.load] or [loads][ujson5.loads] functions, you can either pass in parameters or pass in a subclass of [JSON5Decoder][ujson5.decoder.Json5Decoder] to customize the deserialization process. When passing in the `object_hook` or `pairs_hook` parameter, you can exploit types exposed by the `ujson5` module to enforce type checking. Here is an example: 6 | `ujson5` provides some useful type variables that will help you to enforce type checking when writing object hook functions. Here is an example: 7 | 8 | 9 | ```python 10 | import ujson5 11 | 12 | 13 | def my_obj_hook(dct: ujson5.ObjectHookArg) -> dict: 14 | dct["count"] = len(dct) 15 | return dct 16 | 17 | 18 | data = '{"key": "value", "key2": "value2"}' 19 | deserialized = ujson5.loads(data, object_hook=my_obj_hook) 20 | assert deserialized == {"key": "value", "key2": "value2", "count": 2} 21 | 22 | ``` 23 | 24 | Similarly, you also have the type variable for object pairs hook. Here is an example: 25 | 26 | ```python 27 | import ujson5 28 | 29 | 30 | def my_pairs_hook(pairs: ujson5.ObjectPairsHookArg) -> dict: 31 | dct_pairs = dict(pairs) 32 | dct_pairs["count"] = len(dct_pairs) 33 | return dct_pairs 34 | 35 | 36 | data = '{"key": "value", "key2": "value2"}' 37 | deserialized = ujson5.loads(data, object_pairs_hook=my_pairs_hook) 38 | assert deserialized == {"key": "value", "key2": "value2", "count": 2} 39 | 40 | ``` 41 | 42 | !!! View full API 43 | Checkout the [API Reference](api_reference/decoder.md) for more details on decoding. 44 | -------------------------------------------------------------------------------- /tests/test_snapshots/snapshots/alpha_with_comments.json5: -------------------------------------------------------------------------------- 1 | { 2 | "height": 180, // height of the creature 3 | // weight of the creature 4 | // weight cannot be too high! 5 | "weight": 70, 6 | // age of the human 7 | "age": 30, // human can be very old! 8 | // name of the human 9 | "name": "Alpha", 10 | // human can be very intelligent 11 | "courses": { 12 | // you can also add comments in the TypedDict 13 | "CS101": 90, 14 | // Multi-line comments are also supported 15 | // In this case, the comments in JSON5 will also be multi-line 16 | // The entries of dictionaries that implement this TypedDict will be commented 17 | "ART101": 80, 18 | "HIS101": 70, // a comment can also be in-line 19 | }, // hard-working human 20 | "hobbies": [ 21 | "reading", 22 | "swimming", 23 | "coding", 24 | ], // hobbies takes a lot of time... 25 | "project": { 26 | "project_name": "Alpha's Project", 27 | "pkg_license": "MIT", 28 | // build backends are used to build and distribute your project as a package 29 | "build_backend": "Poetry-core", // This is a comment 30 | // dependency managers are used to manage your project's dependencies 31 | "dependency_manager": "poetry", 32 | // static code checkers are used to check your code for errors 33 | "static_code_checkers": [ 34 | "flake8", 35 | "mypy", 36 | ], 37 | "formatter": [ 38 | "black", 39 | "isort", 40 | ], 41 | "spell_checker": "cspell", // spell checkers! 42 | "docs": "mkdocs", 43 | "code_editor": "vs_code", // code editors are used to edit your code 44 | // pre-commit is used to run checks before committing code 45 | "pre_commit": true, // a comment can also be in-line 46 | "cloud_code_base": "github", 47 | }, 48 | "prop": { 49 | // Property of the house 50 | "house": "Alpha's House", // house name 51 | // Property of the car 52 | "car": "Alpha's Car", // car name, can be None 53 | }, // property of the human 54 | } 55 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | permissions: 10 | contents: write 11 | 12 | jobs: 13 | develop: 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | python-version: ["3.10", "3.11", "3.12", "3.13"] 18 | os: [ubuntu-latest, macos-latest, windows-latest] 19 | defaults: 20 | run: 21 | shell: bash 22 | runs-on: ${{ matrix.os }} 23 | steps: 24 | - name: Check out repository 25 | uses: actions/checkout@v4 26 | with: 27 | fetch-depth: 0 # Fetch all history for all tags and branches 28 | 29 | - name: Set up Python ${{ matrix.python-version }} 30 | uses: actions/setup-python@v5 31 | with: 32 | python-version: ${{ matrix.python-version }} 33 | 34 | - uses: actions/checkout@v4 35 | - name: Install uv 36 | uses: astral-sh/setup-uv@v5 37 | with: 38 | python-version: ${{ matrix.python-version }} 39 | - name: Install dependencies 40 | run: | 41 | uv venv 42 | uv pip install --upgrade pip 43 | uv sync 44 | 45 | - name: Run pytest with coverage 46 | run: | 47 | uv run pytest 48 | - name: Upload coverage to Codecov 49 | uses: codecov/codecov-action@v5 50 | with: 51 | token: ${{ secrets.CODECOV_TOKEN }} 52 | files: ./tests/.coverage/cov.xml 53 | flags: pytest 54 | - name: Upload results 55 | uses: trunk-io/analytics-uploader@main 56 | with: 57 | junit-paths: ./tests/.coverage/cov.xml 58 | org-slug: austinyu 59 | token: ${{ secrets.TRUNK_API_TOKEN }} 60 | continue-on-error: true 61 | 62 | - name: Build package 63 | run: | 64 | uv build 65 | - name: Upload artifact 66 | uses: actions/upload-artifact@v4 67 | with: 68 | name: build-artifacts-${{ runner.os }}-py${{ matrix.python-version }} 69 | path: dist/* 70 | -------------------------------------------------------------------------------- /tests/test_json5_examples.py: -------------------------------------------------------------------------------- 1 | """Test cases provided by the official JSON5 test suite. 2 | 3 | https://github.com/json5/json5-tests 4 | """ 5 | 6 | import re 7 | from pathlib import Path 8 | 9 | import pytest 10 | 11 | import ujson5 12 | 13 | from . import example_consts 14 | 15 | 16 | @pytest.mark.parametrize( 17 | "path", 18 | example_consts.VALID_EXAMPLES, 19 | ) 20 | def test_valid_examples(path: str) -> None: 21 | """Test valid JSON5 examples.""" 22 | with open(path, "r", encoding="utf8") as file: 23 | ujson5.load(file) 24 | 25 | 26 | @pytest.mark.parametrize( 27 | "path", 28 | example_consts.INVALID_EXAMPLES, 29 | ) 30 | def test_invalid_examples(path: str) -> None: 31 | """Test invalid JSON5 examples.""" 32 | with ( 33 | open(path, "r", encoding="utf8") as file, 34 | pytest.raises(ujson5.JSON5DecodeError), 35 | ): 36 | ujson5.load(file) 37 | 38 | 39 | @pytest.mark.parametrize( 40 | "path", 41 | example_consts.VALID_EXAMPLES, 42 | ) 43 | def test_dump_load_from_examples(path: str, tmp_path: Path) -> None: 44 | """Test valid JSON5 examples.""" 45 | with open(path, "r", encoding="utf8") as file: 46 | py_obj = ujson5.load(file) 47 | dump_path_config = tmp_path / "dump_config.json5" 48 | dump_path_default = tmp_path / "dump_default.json5" 49 | with open(path, "r", encoding="utf8") as file: 50 | orig_content: str = file.read() 51 | non_ascii = bool(re.search(r"[^\x00-\x7F]", orig_content)) 52 | with open(dump_path_config, "w", encoding="utf8") as file: 53 | ujson5.dump(py_obj, file, indent=4, ensure_ascii=not non_ascii) 54 | 55 | with open(dump_path_default, "w", encoding="utf8") as file: 56 | ujson5.dump(py_obj, file) 57 | 58 | with open(dump_path_config, "r", encoding="utf8") as file: 59 | new_content = ujson5.load(file) 60 | 61 | with open(dump_path_default, "r", encoding="utf8") as file: 62 | new_content_default = ujson5.load(file) 63 | 64 | if str(py_obj) == "nan": 65 | assert str(new_content) == "nan" 66 | assert str(new_content_default) == "nan" 67 | return 68 | assert py_obj == new_content == new_content_default 69 | -------------------------------------------------------------------------------- /release/README.md: -------------------------------------------------------------------------------- 1 | # Release Instructions 2 | 3 | **Note:** _This should only apply to maintainers when prepare for and publishing a new release._ 4 | 5 | ## Prerequisites 6 | 7 | - `gh` cli is installed - see installation instructions [here](https://docs.github.com/en/github-cli/github-cli/quickstart) 8 | - Run `gh auth login` to authenticate with GitHub, which is needed for the API calls made in the release process. 9 | 10 | ## Semi-automated Release Process 11 | 12 | 1. Run `uv run release/prepare.py {VERSION}` from the root of the repository. This will: 13 | - Update the version number in the `version.py` file and run `uv lock -P ujson5` to update the lock file. 14 | - Add a new section to HISTORY.md with a title containing the version number tag and current date. 15 | 2. Curate the changes in CHANGELOG.md: 16 | - mark any breaking changes with `**Breaking Change:**` 17 | - deduplicate the `packaging` entries to include only the most recent version bumps for each package 18 | 3. Run `trunk fmt` to format CHANGELOG.md. 19 | 4. Run `uv run release/push.py` from the root of the repository. This will: 20 | - Create a PR with the changes you made in the previous steps. 21 | - Add a label to the PR to indicate that it's a release PR. 22 | - Open a draft release on GitHub with the changes you made in the previous steps. 23 | 5. Review the PR and merge it. 24 | 6. Publish the release and wait for the CI to finish building and publishing the new version. 25 | 26 | ## Manual Release Process 27 | 28 | To create a new release: 29 | 30 | 1. Edit `ujson5/version.py` to set the new version number and run `uv lock -P ujson5` 31 | 2. Add a new section to HISTORY.md with a title containing the version number tag and current date in this format , `## {version} ({date})` example: `## v2.11.0a2 (2025-02-10)`. 32 | 3. Copy the changes generated by GitHub and paste them in the new section of CHANGELOG.md. 33 | 4. Create a pull request with these changes. 34 | 5. Once the pull request is merged, create a new release on GitHub: 35 | - the tag should be `v{VERSION}` 36 | - the title should be `v{VERSION} {DATE}` 37 | - the body should contain: 38 | - a copy-paste of the `CHANGELOG.md` section you prepared previously, plus 39 | - a full changelog link in the form `Full Changelog: https://github.com/austinyu/ujson5/compare/v{PREV_VERSION}...v{VERSION}/` 40 | -------------------------------------------------------------------------------- /tests/test_native_json_benchmark.py: -------------------------------------------------------------------------------- 1 | """https://github.com/miloyip/nativejson-benchmark""" 2 | 3 | import os 4 | from pathlib import Path 5 | 6 | import pytest 7 | 8 | import ujson5 9 | 10 | BASE_FOLDER = Path(os.path.dirname(__file__)) / "native_json_benchmark" 11 | 12 | JSON_CHECKER_FOLDER = BASE_FOLDER / "jsonchecker" 13 | JSON_CHECKER_PATHS: list[Path] = [ 14 | f for f in JSON_CHECKER_FOLDER.iterdir() if f.is_file() if f.name.startswith("pass") 15 | ] 16 | 17 | 18 | @pytest.mark.parametrize("file_path", JSON_CHECKER_PATHS) 19 | def test_json_checker_file(file_path: Path) -> None: 20 | """Test for JSON checker files.""" 21 | with open(file_path, "r", encoding="utf8") as file: 22 | ujson5.load(file, strict=False) 23 | 24 | 25 | ROUND_TRIP_FOLDER = BASE_FOLDER / "roundtrip" 26 | ROUND_TRIP_PATHS: list[Path] = list(ROUND_TRIP_FOLDER.iterdir()) 27 | 28 | 29 | @pytest.mark.parametrize("file_path", ROUND_TRIP_PATHS) 30 | def test_round_trips(file_path: Path) -> None: 31 | """Test for loading and dumping.""" 32 | with open(file_path, "r", encoding="utf8") as file: 33 | data = ujson5.load(file, strict=False) 34 | assert data == ujson5.loads(ujson5.dumps(data)) 35 | 36 | 37 | @pytest.mark.skipif(not os.getenv("CI_ENV"), reason="Run only in CI environment") 38 | def test_loading_canada_file(benchmark) -> None: # pragma: no cover 39 | """Test for loading large files.""" 40 | with open(BASE_FOLDER / "canada.json", "r", encoding="utf8") as file: 41 | content: str = file.read() 42 | benchmark(ujson5.loads, content, strict=False) 43 | 44 | 45 | @pytest.mark.skipif(not os.getenv("CI_ENV"), reason="Run only in CI environment") 46 | def test_loading_citm_catalog_file(benchmark) -> None: # pragma: no cover 47 | """Test for loading large files.""" 48 | with open(BASE_FOLDER / "citm_catalog.json", "r", encoding="utf8") as file: 49 | content: str = file.read() 50 | benchmark(ujson5.loads, content, strict=False) 51 | 52 | 53 | @pytest.mark.skipif(not os.getenv("CI_ENV"), reason="Run only in CI environment") 54 | def test_loading_citm_twitter_file(benchmark) -> None: # pragma: no cover 55 | """Test for loading large files.""" 56 | with open(BASE_FOLDER / "twitter.json", "r", encoding="utf8") as file: 57 | content: str = file.read() 58 | benchmark(ujson5.loads, content, strict=False) 59 | -------------------------------------------------------------------------------- /tests/test_unit_tests/test_identifier_lexer.py: -------------------------------------------------------------------------------- 1 | """Test the identifier lexer.""" 2 | 3 | from copy import copy 4 | from random import choice, randint, sample 5 | 6 | import pytest 7 | 8 | from ujson5.consts import ( 9 | PUNCTUATORS, 10 | UNICODE_COMBINING_MARKS, 11 | UNICODE_CONNECTORS, 12 | UNICODE_DIGITS, 13 | UNICODE_LETTERS, 14 | ZWJ, 15 | ZWNJ, 16 | ) 17 | from ujson5.core import TOKEN_TYPE, JSON5DecodeError 18 | from ujson5.lexer import tokenize_identifier 19 | 20 | unicode_letters = copy(UNICODE_LETTERS) 21 | unicode_combining_marks = copy(UNICODE_COMBINING_MARKS) 22 | unicode_digits = copy(UNICODE_DIGITS) 23 | unicode_connectors = copy(UNICODE_CONNECTORS) 24 | 25 | VALID_HEX_DIGITS = "0123456789abcdefABCDEF" 26 | RANDOM_UNICODE_ESCAPE = ( 27 | f"\\u{choice(VALID_HEX_DIGITS)}{choice(VALID_HEX_DIGITS)}" 28 | + f"{choice(VALID_HEX_DIGITS)}{choice(VALID_HEX_DIGITS)}" 29 | ) 30 | 31 | 32 | @pytest.mark.parametrize( 33 | "identifier, start, end", 34 | [ 35 | ("a", 0, 1), 36 | ("A", 0, 1), 37 | ("_A", 0, 2), 38 | ("$A", 0, 2), 39 | (RANDOM_UNICODE_ESCAPE, 0, 6), 40 | (f"a02a{' ' * randint(0, 10)}", 0, 4), 41 | *[(f"_\\u0312{p} ", 0, 7) for p in PUNCTUATORS], 42 | (f"{unicode_letters.pop()}{unicode_combining_marks.pop()}", 0, 2), 43 | (f"{unicode_letters.pop()}{ZWJ}{ZWNJ}", 0, 3), 44 | (f"{unicode_letters.pop()}{unicode_digits.pop()}", 0, 2), 45 | (f"{unicode_letters.pop()}{unicode_connectors.pop()}", 0, 2), 46 | ], 47 | ) 48 | def test_valid_identifiers(identifier: str, start: int, end: int) -> None: 49 | """Test valid identifiers.""" 50 | result = tokenize_identifier(buffer=identifier, idx=0) 51 | assert result.token is not None 52 | assert result.token.tk_type == TOKEN_TYPE["IDENTIFIER"] 53 | r_start, r_end = result.token.value 54 | assert (r_start, r_end) == (start, end) 55 | 56 | 57 | @pytest.mark.parametrize( 58 | "identifier", 59 | [ 60 | "\\u22\\xab", 61 | "\\u", 62 | *sample(list(unicode_combining_marks), k=min(10, len(unicode_combining_marks))), 63 | *sample(list(unicode_digits), k=min(10, len(unicode_digits))), 64 | *sample(list(unicode_connectors), k=min(10, len(unicode_connectors))), 65 | "A\u2603", # invalid unicode escape sequence 66 | ], 67 | ) 68 | def test_invalid_identifiers(identifier: str) -> None: 69 | """Test invalid identifiers.""" 70 | with pytest.raises(JSON5DecodeError): 71 | tokenize_identifier(buffer=identifier, idx=0) 72 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: ujson5 2 | site_url: https://austinyu.github.io/ujson5/ 3 | 4 | theme: 5 | name: material 6 | palette: 7 | - media: "(prefers-color-scheme)" 8 | scheme: default 9 | primary: orange 10 | accent: amber 11 | toggle: 12 | icon: material/weather-sunny 13 | name: "Switch to light mode" 14 | - media: "(prefers-color-scheme: light)" 15 | scheme: default 16 | primary: orange 17 | accent: amber 18 | toggle: 19 | icon: material/weather-night 20 | name: "Switch to dark mode" 21 | - media: "(prefers-color-scheme: dark)" 22 | scheme: slate 23 | primary: orange 24 | accent: amber 25 | toggle: 26 | icon: material/lightbulb-auto-outline 27 | name: "Switch to system preference" 28 | features: 29 | - content.tabs.link 30 | - content.code.annotate 31 | - content.code.copy 32 | - announce.dismiss 33 | - navigation.tabs 34 | - navigation.instant 35 | - navigation.instant.prefetch 36 | - navigation.instant.preview 37 | - navigation.instant.progress 38 | - navigation.path 39 | - navigation.sections 40 | - navigation.top 41 | - navigation.tracking 42 | - search.suggest 43 | - toc.follow 44 | 45 | repo_name: austinyu/ujson5 46 | repo_url: https://github.com/austinyu/ujson5 47 | 48 | plugins: 49 | - mkdocstrings: 50 | handlers: 51 | python: 52 | paths: [src] 53 | options: 54 | docstring_style: google 55 | members_order: source 56 | separate_signature: true 57 | filters: ["!^_"] 58 | docstring_options: 59 | ignore_init_summary: true 60 | merge_init_into_class: true 61 | show_signature_annotations: true 62 | signature_crossrefs: true 63 | inventories: 64 | - url: https://docs.python.org/3/objects.inv 65 | domains: [py, std] 66 | - search 67 | 68 | 69 | markdown_extensions: 70 | - tables 71 | - toc: 72 | permalink: true 73 | title: Page contents 74 | - admonition 75 | - pymdownx.details 76 | - pymdownx.superfences 77 | - pymdownx.highlight: 78 | pygments_lang_class: true 79 | - pymdownx.extra 80 | - pymdownx.tabbed: 81 | alternate_style: true 82 | 83 | nav: 84 | - Home: 85 | - Welcome to ujson5: index.md 86 | - Quick Start Encoding: start_encoding.md 87 | - Quick Start Decoding: start_decoding.md 88 | - Contributing: contributing.md 89 | - API Reference: 90 | - Core: api_reference/core.md 91 | - Decoder: api_reference/decoder.md 92 | - Encoder: api_reference/encoder.md 93 | - About: 94 | - About ujson5: about.md 95 | -------------------------------------------------------------------------------- /tests/json5_examples/misc/npm-package.json5: -------------------------------------------------------------------------------- 1 | { 2 | name: 'npm', 3 | publishConfig: { 4 | 'proprietary-attribs': false, 5 | }, 6 | description: 'A package manager for node', 7 | keywords: [ 8 | 'package manager', 9 | 'modules', 10 | 'install', 11 | 'package.json', 12 | ], 13 | version: '1.1.22', 14 | preferGlobal: true, 15 | config: { 16 | publishtest: false, 17 | }, 18 | homepage: 'http://npmjs.org/', 19 | author: 'Isaac Z. Schlueter (http://blog.izs.me)', 20 | repository: { 21 | type: 'git', 22 | url: 'https://github.com/isaacs/npm', 23 | }, 24 | bugs: { 25 | email: 'npm-@googlegroups.com', 26 | url: 'http://github.com/isaacs/npm/issues', 27 | }, 28 | directories: { 29 | doc: './doc', 30 | man: './man', 31 | lib: './lib', 32 | bin: './bin', 33 | }, 34 | main: './lib/npm.js', 35 | bin: './bin/npm-cli.js', 36 | dependencies: { 37 | semver: '~1.0.14', 38 | ini: '1', 39 | slide: '1', 40 | abbrev: '1', 41 | 'graceful-fs': '~1.1.1', 42 | minimatch: '~0.2', 43 | nopt: '1', 44 | 'node-uuid': '~1.3', 45 | 'proto-list': '1', 46 | rimraf: '2', 47 | request: '~2.9', 48 | which: '1', 49 | tar: '~0.1.12', 50 | fstream: '~0.1.17', 51 | 'block-stream': '*', 52 | inherits: '1', 53 | mkdirp: '0.3', 54 | read: '0', 55 | 'lru-cache': '1', 56 | 'node-gyp': '~0.4.1', 57 | 'fstream-npm': '0 >=0.0.5', 58 | 'uid-number': '0', 59 | archy: '0', 60 | chownr: '0', 61 | }, 62 | bundleDependencies: [ 63 | 'slide', 64 | 'ini', 65 | 'semver', 66 | 'abbrev', 67 | 'graceful-fs', 68 | 'minimatch', 69 | 'nopt', 70 | 'node-uuid', 71 | 'rimraf', 72 | 'request', 73 | 'proto-list', 74 | 'which', 75 | 'tar', 76 | 'fstream', 77 | 'block-stream', 78 | 'inherits', 79 | 'mkdirp', 80 | 'read', 81 | 'lru-cache', 82 | 'node-gyp', 83 | 'fstream-npm', 84 | 'uid-number', 85 | 'archy', 86 | 'chownr', 87 | ], 88 | devDependencies: { 89 | ronn: 'https://github.com/isaacs/ronnjs/tarball/master', 90 | }, 91 | engines: { 92 | node: '0.6 || 0.7 || 0.8', 93 | npm: '1', 94 | }, 95 | scripts: { 96 | test: 'node ./test/run.js', 97 | prepublish: 'npm prune; rm -rf node_modules/*/{test,example,bench}*; make -j4 doc', 98 | dumpconf: 'env | grep npm | sort | uniq', 99 | }, 100 | licenses: [ 101 | { 102 | type: 'MIT +no-false-attribs', 103 | url: 'http://github.com/isaacs/npm/raw/master/LICENSE', 104 | }, 105 | ], 106 | } 107 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # pre-commit autoupdate 2 | 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v5.0.0 6 | hooks: 7 | - id: end-of-file-fixer 8 | exclude: ^tests/.*\.json$|^tests/.*\.json5$|^tests/.*\.errorSpec$|^tests/.*\.txt$|^tests/.*\.js$ 9 | - id: trailing-whitespace 10 | exclude: ^tests/.*\.json$|^tests/.*\.json5$ 11 | - id: check-yaml 12 | - id: check-toml 13 | - id: check-added-large-files 14 | 15 | - repo: https://github.com/PyCQA/autoflake 16 | rev: v2.3.1 17 | hooks: 18 | - id: autoflake 19 | args: 20 | [--remove-all-unused-imports, --remove-unused-variables, --in-place] 21 | 22 | - repo: local 23 | hooks: 24 | - id: isort 25 | name: isort 26 | entry: uv run isort . 27 | types: [python] 28 | language: system 29 | pass_filenames: false 30 | - id: trunk-fmt 31 | name: trunk fmt 32 | entry: trunk fmt 33 | language: system 34 | 35 | - repo: https://github.com/astral-sh/ruff-pre-commit 36 | # Ruff version. 37 | rev: v0.11.0 38 | hooks: 39 | # Run the linter. 40 | - id: ruff 41 | args: [--fix] 42 | # Run the formatter. 43 | - id: ruff-format 44 | 45 | - repo: local 46 | hooks: 47 | - id: flake8 48 | name: flake8 49 | entry: uv run flake8 50 | types: [python] 51 | language: system 52 | pass_filenames: false 53 | args: [src, tests] 54 | - id: pylint 55 | name: pylint 56 | entry: pylint 57 | language: system 58 | types: [python] 59 | require_serial: true 60 | args: [ 61 | src, 62 | tests, 63 | -rn, # Only display messages 64 | -sn, # Don't display the score 65 | --rcfile=.pylintrc, 66 | ] 67 | - id: mypy 68 | name: Run mypy with uv 69 | entry: uv run mypy 70 | language: system 71 | types: [python] 72 | pass_filenames: false 73 | args: [src, tests] 74 | - id: trunk 75 | name: Run trunk checks 76 | entry: trunk check 77 | language: system 78 | 79 | - repo: https://github.com/streetsidesoftware/cspell-cli 80 | rev: v8.17.2 81 | hooks: 82 | - id: cspell # Spell check changed files 83 | - id: cspell # Spell check the commit message 84 | name: check commit message spelling 85 | args: 86 | - --no-must-find-files 87 | - --no-progress 88 | - --no-summary 89 | - --files 90 | - .git/COMMIT_EDITMSG 91 | stages: [commit-msg] 92 | always_run: true 93 | -------------------------------------------------------------------------------- /tests/json5_examples/misc/npm-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm", 3 | "publishConfig": { 4 | "proprietary-attribs": false 5 | }, 6 | "description": "A package manager for node", 7 | "keywords": [ 8 | "package manager", 9 | "modules", 10 | "install", 11 | "package.json" 12 | ], 13 | "version": "1.1.22", 14 | "preferGlobal": true, 15 | "config": { 16 | "publishtest": false 17 | }, 18 | "homepage": "http://npmjs.org/", 19 | "author": "Isaac Z. Schlueter (http://blog.izs.me)", 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/isaacs/npm" 23 | }, 24 | "bugs": { 25 | "email": "npm-@googlegroups.com", 26 | "url": "http://github.com/isaacs/npm/issues" 27 | }, 28 | "directories": { 29 | "doc": "./doc", 30 | "man": "./man", 31 | "lib": "./lib", 32 | "bin": "./bin" 33 | }, 34 | "main": "./lib/npm.js", 35 | "bin": "./bin/npm-cli.js", 36 | "dependencies": { 37 | "semver": "~1.0.14", 38 | "ini": "1", 39 | "slide": "1", 40 | "abbrev": "1", 41 | "graceful-fs": "~1.1.1", 42 | "minimatch": "~0.2", 43 | "nopt": "1", 44 | "node-uuid": "~1.3", 45 | "proto-list": "1", 46 | "rimraf": "2", 47 | "request": "~2.9", 48 | "which": "1", 49 | "tar": "~0.1.12", 50 | "fstream": "~0.1.17", 51 | "block-stream": "*", 52 | "inherits": "1", 53 | "mkdirp": "0.3", 54 | "read": "0", 55 | "lru-cache": "1", 56 | "node-gyp": "~0.4.1", 57 | "fstream-npm": "0 >=0.0.5", 58 | "uid-number": "0", 59 | "archy": "0", 60 | "chownr": "0" 61 | }, 62 | "bundleDependencies": [ 63 | "slide", 64 | "ini", 65 | "semver", 66 | "abbrev", 67 | "graceful-fs", 68 | "minimatch", 69 | "nopt", 70 | "node-uuid", 71 | "rimraf", 72 | "request", 73 | "proto-list", 74 | "which", 75 | "tar", 76 | "fstream", 77 | "block-stream", 78 | "inherits", 79 | "mkdirp", 80 | "read", 81 | "lru-cache", 82 | "node-gyp", 83 | "fstream-npm", 84 | "uid-number", 85 | "archy", 86 | "chownr" 87 | ], 88 | "devDependencies": { 89 | "ronn": "https://github.com/isaacs/ronnjs/tarball/master" 90 | }, 91 | "engines": { 92 | "node": "0.6 || 0.7 || 0.8", 93 | "npm": "1" 94 | }, 95 | "scripts": { 96 | "test": "node ./test/run.js", 97 | "prepublish": "npm prune; rm -rf node_modules/*/{test,example,bench}*; make -j4 doc", 98 | "dumpconf": "env | grep npm | sort | uniq" 99 | }, 100 | "licenses": [ 101 | { 102 | "type": "MIT +no-false-attribs", 103 | "url": "http://github.com/isaacs/npm/raw/master/LICENSE" 104 | } 105 | ] 106 | } 107 | -------------------------------------------------------------------------------- /tests/test_snapshots/generate_snapshots.py: -------------------------------------------------------------------------------- 1 | """Generate snapshots for snapshot tests. If you want to update the snapshots, run this script. 2 | Snapshot tests are used to test the consistency of the dump and load functions. 3 | """ 4 | 5 | import snapshots # type: ignore 6 | 7 | import ujson5 8 | 9 | 10 | def dump_alpha() -> None: 11 | """Dump json5 for alpha obj.""" 12 | with open( 13 | snapshots.SNAPSHOTS_ROOT / snapshots.SNAPSHOT_NAMES["alpha_default"], 14 | "w", 15 | encoding="utf8", 16 | ) as file: 17 | ujson5.dump(snapshots.ALPHA, file) 18 | 19 | with open( 20 | snapshots.SNAPSHOTS_ROOT / snapshots.SNAPSHOT_NAMES["alpha_with_comments"], 21 | "w", 22 | encoding="utf8", 23 | ) as file: 24 | ujson5.dump( 25 | snapshots.ALPHA, file, snapshots.Human, indent=snapshots.DEFAULT_INDENT 26 | ) 27 | with open( 28 | snapshots.SNAPSHOTS_ROOT / snapshots.SNAPSHOT_NAMES["alpha_no_comments"], 29 | "w", 30 | encoding="utf8", 31 | ) as file: 32 | ujson5.dump(snapshots.ALPHA, file, indent=snapshots.DEFAULT_INDENT) 33 | 34 | with open( 35 | snapshots.SNAPSHOTS_ROOT / snapshots.SNAPSHOT_NAMES["alpha_no_indent"], 36 | "w", 37 | encoding="utf8", 38 | ) as file: 39 | ujson5.dump(snapshots.ALPHA, file) 40 | 41 | with open( 42 | snapshots.SNAPSHOTS_ROOT / snapshots.SNAPSHOT_NAMES["alpha_7_indent"], 43 | "w", 44 | encoding="utf8", 45 | ) as file: 46 | ujson5.dump(snapshots.ALPHA, file, indent=7) 47 | 48 | with open( 49 | snapshots.SNAPSHOTS_ROOT / snapshots.SNAPSHOT_NAMES["alpha_special_separators"], 50 | "w", 51 | encoding="utf8", 52 | ) as file: 53 | ujson5.dump( 54 | snapshots.ALPHA, 55 | file, 56 | indent=snapshots.DEFAULT_INDENT, 57 | separators=("|", "->"), 58 | ) 59 | 60 | with open( 61 | snapshots.SNAPSHOTS_ROOT 62 | / snapshots.SNAPSHOT_NAMES["alpha_with_trailing_comma"], 63 | "w", 64 | encoding="utf8", 65 | ) as file: 66 | ujson5.dump( 67 | snapshots.ALPHA, 68 | file, 69 | indent=snapshots.DEFAULT_INDENT, 70 | trailing_comma=True, 71 | ) 72 | 73 | with open( 74 | snapshots.SNAPSHOTS_ROOT / snapshots.SNAPSHOT_NAMES["alpha_no_trailing_comma"], 75 | "w", 76 | encoding="utf8", 77 | ) as file: 78 | ujson5.dump( 79 | snapshots.ALPHA, 80 | file, 81 | indent=snapshots.DEFAULT_INDENT, 82 | trailing_comma=False, 83 | ) 84 | 85 | 86 | if __name__ == "__main__": 87 | dump_alpha() 88 | print("Snapshots generated successfully. 🎉") 89 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | """Test cli functionally.""" 2 | 3 | import io 4 | from contextlib import redirect_stdout 5 | from pathlib import Path 6 | from random import choice 7 | 8 | import pytest 9 | 10 | import ujson5 11 | from ujson5 import cli 12 | 13 | from . import example_consts 14 | 15 | 16 | @pytest.mark.parametrize("arg", ["--version", "-v"]) 17 | def test_cli_version(arg: str) -> None: 18 | """Test version output.""" 19 | with redirect_stdout(io.StringIO()) as f: 20 | cli.main([arg]) 21 | assert f.getvalue().strip() == ujson5.__version__ 22 | 23 | 24 | @pytest.mark.parametrize("arg", ["--info", "-i"]) 25 | def test_cli_info(arg: str) -> None: 26 | """Test version info output.""" 27 | with redirect_stdout(io.StringIO()) as f: 28 | cli.main([arg]) 29 | assert f.getvalue().strip() == ujson5.version_info() 30 | 31 | 32 | def test_cli_stdout_correct() -> None: 33 | """Test stdout output.""" 34 | with redirect_stdout(io.StringIO()) as f: 35 | cli.main([str(choice(example_consts.VALID_EXAMPLES))]) 36 | assert cli.JSON_CONVERTED in f.getvalue().strip() 37 | 38 | 39 | def test_cli_stdout_incorrect() -> None: 40 | """Test stdout output.""" 41 | with redirect_stdout(io.StringIO()) as f: 42 | cli.main([str(choice(example_consts.INVALID_EXAMPLES))]) 43 | assert cli.DECODING_ERROR in f.getvalue().strip() 44 | 45 | 46 | def test_cli_no_target(monkeypatch) -> None: 47 | """Test no target.""" 48 | monkeypatch.setattr("sys.stdin.isatty", lambda: True) 49 | with redirect_stdout(io.StringIO()) as f: 50 | cli.main([]) 51 | assert cli.ERR_NO_TARGET in f.getvalue().strip() 52 | 53 | 54 | def test_cli_stdin(monkeypatch) -> None: 55 | """Test reading from stdin with options.""" 56 | monkeypatch.setattr("sys.stdin", io.StringIO('{"json": "obj"}')) 57 | with redirect_stdout(io.StringIO()) as f: 58 | cli.main(["--no-indent"]) 59 | assert '{"json": "obj"}' in f.getvalue().strip() 60 | assert cli.JSON_CONVERTED in f.getvalue().strip() 61 | 62 | monkeypatch.setattr("sys.stdin", io.StringIO('{"json": "obj"}')) 63 | with redirect_stdout(io.StringIO()) as f: 64 | cli.main(["--compact"]) 65 | assert '{"json":"obj"}' in f.getvalue().strip() 66 | assert cli.JSON_CONVERTED in f.getvalue().strip() 67 | 68 | 69 | def test_cli_invalid_path() -> None: 70 | """Test invalid path.""" 71 | with redirect_stdout(io.StringIO()) as f: 72 | cli.main([str(choice(example_consts.INVALID_EXAMPLES).parent / "wrong.json5")]) 73 | assert cli.ERR_TARGET_NOT_EXIST in f.getvalue().strip() 74 | 75 | 76 | def test_cli_output(tmp_path: Path) -> None: 77 | """Test output file.""" 78 | target: Path = choice(example_consts.VALID_EXAMPLES) 79 | output: Path = tmp_path / "output.json5" 80 | assert not output.exists() 81 | cli.main([str(target), str(output)]) 82 | assert output.exists() 83 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ['hatchling', "hatch-vcs", 'hatch-fancy-pypi-readme>=22.5.0'] 3 | build-backend = 'hatchling.build' 4 | 5 | 6 | [project] 7 | name = "ujson5" 8 | description = "A fast JSON5 encoder/decoder for Python" 9 | authors = [{ name = "Austin Yu", email = "yuxm.austin1023@gmail.com" }] 10 | license = { text = "MIT" } 11 | requires-python = ">=3.10" 12 | dependencies = [] 13 | classifiers = [ 14 | 'Development Status :: 2 - Pre-Alpha', 15 | 'Programming Language :: Python', 16 | 'Programming Language :: Python :: Implementation :: CPython', 17 | 'Programming Language :: Python :: Implementation :: PyPy', 18 | 'Programming Language :: Python :: 3', 19 | 'Programming Language :: Python :: 3 :: Only', 20 | 'Programming Language :: Python :: 3.10', 21 | 'Programming Language :: Python :: 3.11', 22 | 'Programming Language :: Python :: 3.12', 23 | 'Programming Language :: Python :: 3.13', 24 | 'Intended Audience :: Developers', 25 | 'Intended Audience :: Information Technology', 26 | 'License :: OSI Approved :: MIT License', 27 | 'Operating System :: OS Independent', 28 | 'Topic :: Software Development :: Libraries :: Python Modules', 29 | 'Topic :: Internet', 30 | ] 31 | dynamic = ['version', 'readme'] 32 | 33 | [project.urls] 34 | Homepage = 'https://github.com/austinyu/ujson5' 35 | Documentation = 'https://austinyu.github.io/ujson5/' 36 | Source = 'https://github.com/austinyu/ujson5' 37 | # Changelog = TBD 38 | 39 | [project.scripts] 40 | ujson5 = "ujson5.cli:main" 41 | 42 | 43 | [dependency-groups] 44 | dev = ["requests", "types-requests"] 45 | 46 | tests = [ 47 | "pytest", 48 | "pytest-cov", 49 | "pytest-benchmark", 50 | "pytest-codspeed", 51 | "pytest-test-groups", 52 | ] 53 | 54 | static_checkers = [ 55 | "pylint", 56 | "mypy", 57 | "flake8", 58 | "flake8-simplify", 59 | "flake8-mutable", 60 | "flake8-print", 61 | "flake8-use-fstring", 62 | "flake8-builtins", 63 | "flake8-functions-names", 64 | "flake8-variables-names", 65 | "flake8-no-implicit-concat", 66 | ] 67 | 68 | formatters = ["ruff", "isort"] 69 | 70 | docs = [ 71 | "mkdocs", 72 | "mkdocs-material", 73 | "mkdocstrings-python", 74 | "pymdown-extensions", 75 | ] 76 | 77 | all = [ 78 | { include-group = "dev" }, 79 | { include-group = "tests" }, 80 | { include-group = "static_checkers" }, 81 | { include-group = "formatters" }, 82 | { include-group = "docs" }, 83 | ] 84 | 85 | [tool.uv] 86 | default-groups = ['all'] 87 | 88 | [tool.hatch.version] 89 | source = "vcs" 90 | 91 | [tool.hatch.metadata.hooks.fancy-pypi-readme] 92 | content-type = 'text/markdown' 93 | # construct the PyPI readme from README.md and CHANGELOG.md 94 | fragments = [ 95 | { path = 'README.md' }, 96 | { text = "\n## Changelog\n\n" }, 97 | { path = 'CHANGELOG.md', pattern = '(.+?)' }, 98 | ] 99 | 100 | [tool.hatch.build.targets.sdist] 101 | include = ['/README.md', '/CHANGELOG.md', '/src', '/tests'] 102 | 103 | [tool.hatch.build.hooks.vcs] 104 | version-file = "src/ujson5/_version.py" 105 | 106 | [tool.pytest.ini_options] 107 | addopts = """ 108 | --cov . 109 | --cov-report xml:tests/.coverage/cov.xml 110 | --cov-report html:tests/.coverage/html 111 | """ 112 | 113 | [tool.coverage.report] 114 | exclude_also = ['pytest.skip', 'if sys.version_info < (3, 12): '] 115 | 116 | [tool.coverage.run] 117 | omit = ["tests/test_snapshots/generate_snapshots.py", "tests/test_benchmark.py"] 118 | -------------------------------------------------------------------------------- /tests/test_unit_tests/test_lexer.py: -------------------------------------------------------------------------------- 1 | """Test lexer module""" 2 | 3 | from ujson5.lexer import TOKEN_TYPE, tokenize 4 | 5 | JSON5_TEXT = """{ 6 | // comments 7 | unquoted: 'and you can quote me on that', 8 | singleQuotes: 'I can use "double quotes" here', 9 | lineBreaks: "Look, Mom! \\ 10 | No \\\\n's!", 11 | hexadecimal: 0xdecaf, 12 | leadingDecimalPoint: .8675309, andTrailing: 8675309., 13 | positiveSign: +1, 14 | trailingComma: 'in objects', andIn: ['arrays',], 15 | "backwardsCompatible": "with JSON", 16 | null_supported: null, 17 | infinities_supported: Infinity, 18 | NaN_supported: NaN, 19 | }""" 20 | 21 | tokens: list[tuple[int, str]] = [ 22 | (TOKEN_TYPE["PUN_OPEN_BRACE"], "{"), 23 | (TOKEN_TYPE["IDENTIFIER"], "unquoted"), 24 | (TOKEN_TYPE["PUN_COLON"], ":"), 25 | (TOKEN_TYPE["STRING"], "and you can quote me on that"), 26 | (TOKEN_TYPE["PUN_COMMA"], ","), 27 | (TOKEN_TYPE["IDENTIFIER"], "singleQuotes"), 28 | (TOKEN_TYPE["PUN_COLON"], ":"), 29 | (TOKEN_TYPE["STRING"], 'I can use "double quotes" here'), 30 | (TOKEN_TYPE["PUN_COMMA"], ","), 31 | (TOKEN_TYPE["IDENTIFIER"], "lineBreaks"), 32 | (TOKEN_TYPE["PUN_COLON"], ":"), 33 | (TOKEN_TYPE["STRING"], "Look, Mom! \\\nNo \\\\n's!"), 34 | (TOKEN_TYPE["PUN_COMMA"], ","), 35 | (TOKEN_TYPE["IDENTIFIER"], "hexadecimal"), 36 | (TOKEN_TYPE["PUN_COLON"], ":"), 37 | (TOKEN_TYPE["NUMBER"], "0xdecaf"), 38 | (TOKEN_TYPE["PUN_COMMA"], ","), 39 | (TOKEN_TYPE["IDENTIFIER"], "leadingDecimalPoint"), 40 | (TOKEN_TYPE["PUN_COLON"], ":"), 41 | (TOKEN_TYPE["NUMBER"], ".8675309"), 42 | (TOKEN_TYPE["PUN_COMMA"], ","), 43 | (TOKEN_TYPE["IDENTIFIER"], "andTrailing"), 44 | (TOKEN_TYPE["PUN_COLON"], ":"), 45 | (TOKEN_TYPE["NUMBER"], "8675309."), 46 | (TOKEN_TYPE["PUN_COMMA"], ","), 47 | (TOKEN_TYPE["IDENTIFIER"], "positiveSign"), 48 | (TOKEN_TYPE["PUN_COLON"], ":"), 49 | (TOKEN_TYPE["NUMBER"], "+1"), 50 | (TOKEN_TYPE["PUN_COMMA"], ","), 51 | (TOKEN_TYPE["IDENTIFIER"], "trailingComma"), 52 | (TOKEN_TYPE["PUN_COLON"], ":"), 53 | (TOKEN_TYPE["STRING"], "in objects"), 54 | (TOKEN_TYPE["PUN_COMMA"], ","), 55 | (TOKEN_TYPE["IDENTIFIER"], "andIn"), 56 | (TOKEN_TYPE["PUN_COLON"], ":"), 57 | (TOKEN_TYPE["PUN_OPEN_BRACKET"], "["), 58 | (TOKEN_TYPE["STRING"], "arrays"), 59 | (TOKEN_TYPE["PUN_COMMA"], ","), 60 | (TOKEN_TYPE["PUN_CLOSE_BRACKET"], "]"), 61 | (TOKEN_TYPE["PUN_COMMA"], ","), 62 | (TOKEN_TYPE["STRING"], "backwardsCompatible"), 63 | (TOKEN_TYPE["PUN_COLON"], ":"), 64 | (TOKEN_TYPE["STRING"], "with JSON"), 65 | (TOKEN_TYPE["PUN_COMMA"], ","), 66 | (TOKEN_TYPE["IDENTIFIER"], "null_supported"), 67 | (TOKEN_TYPE["PUN_COLON"], ":"), 68 | (TOKEN_TYPE["NULL"], "null"), 69 | (TOKEN_TYPE["PUN_COMMA"], ","), 70 | (TOKEN_TYPE["IDENTIFIER"], "infinities_supported"), 71 | (TOKEN_TYPE["PUN_COLON"], ":"), 72 | (TOKEN_TYPE["NUMBER"], "Infinity"), 73 | (TOKEN_TYPE["PUN_COMMA"], ","), 74 | (TOKEN_TYPE["IDENTIFIER"], "NaN_supported"), 75 | (TOKEN_TYPE["PUN_COLON"], ":"), 76 | (TOKEN_TYPE["NUMBER"], "NaN"), 77 | (TOKEN_TYPE["PUN_COMMA"], ","), 78 | (TOKEN_TYPE["PUN_CLOSE_BRACE"], "}"), 79 | ] 80 | 81 | 82 | def test_lexer() -> None: 83 | """Test lexer""" 84 | results = tokenize(JSON5_TEXT) 85 | assert len(results) == len(tokens) 86 | for result, tok in zip(results, tokens, strict=False): 87 | assert result.tk_type == tok[0] 88 | r_text = JSON5_TEXT[result.value[0] : result.value[1]] 89 | assert r_text == tok[1] 90 | -------------------------------------------------------------------------------- /src/ujson5/core.py: -------------------------------------------------------------------------------- 1 | """Core JSON5 classes and exceptions.""" 2 | 3 | from typing import Literal, NamedTuple 4 | 5 | from ._version import __version__ 6 | 7 | 8 | def version_info() -> str: 9 | """Return complete version information for ujson5 and its dependencies.""" 10 | import platform # pylint: disable=C0415 11 | import sys # pylint: disable=C0415 12 | 13 | info = { 14 | "ujson5 version": __version__, 15 | "python version": sys.version, 16 | "platform": platform.platform(), 17 | } 18 | info = {k: str(v).replace("\n", " ") for k, v in info.items()} 19 | return "\n".join(f"{k}: {v}" for k, v in info.items()) 20 | 21 | 22 | JsonValue = dict | list | int | float | str | None | bool 23 | """Type hint for JSON5 values.""" 24 | JsonValuePairs = list[tuple[str, JsonValue]] 25 | 26 | 27 | class JSON5DecodeError(ValueError): 28 | """Subclass of ValueError with the following additional properties: 29 | 30 | msg: The unformatted error message 31 | doc: The JSON document being parsed 32 | pos: The start index of doc where parsing failed 33 | lineno: The line corresponding to pos 34 | colno: The column corresponding to pos 35 | 36 | """ 37 | 38 | # Note that this exception is used from _json 39 | def __init__(self, msg: str, doc: str, pos: int) -> None: 40 | lineno = doc.count("\n", 0, pos) + 1 41 | colno = pos - doc.rfind("\n", 0, pos) 42 | err_msg = f"{msg}: line {lineno} column {colno} (char {pos})" 43 | ValueError.__init__(self, err_msg) 44 | self.msg = msg 45 | self.doc = doc 46 | self.pos = pos 47 | self.lineno = lineno 48 | self.colno = colno 49 | 50 | def __reduce__(self) -> tuple: # pragma: no cover 51 | return self.__class__, (self.msg, self.doc, self.pos) 52 | 53 | def __str__(self) -> str: # pragma: no cover 54 | # Get the line where the error occurred 55 | line_start = self.doc.rfind("\n", 0, self.pos) + 1 56 | line_end = self.doc.find("\n", self.pos) 57 | if line_end == -1: 58 | line_end = len(self.doc) 59 | error_line = self.doc[line_start:line_end] 60 | 61 | # Create a pointer to the error column 62 | pointer = " " * (self.colno - 1) + "^" 63 | 64 | # Format the error message 65 | return ( 66 | f"{self.msg}: line {self.lineno} column {self.colno} (char {self.pos})\n" 67 | + f"{error_line}\n" 68 | + f"{pointer}" 69 | ) 70 | 71 | 72 | class JSON5EncodeError(ValueError): 73 | """Subclass of ValueError raised when encoding fails.""" 74 | 75 | 76 | TokenTypesKey = Literal[ 77 | "IDENTIFIER", 78 | "STRING", 79 | "NUMBER", 80 | "BOOLEAN", 81 | "NULL", 82 | "PUN_OPEN_BRACE", 83 | "PUN_CLOSE_BRACE", 84 | "PUN_OPEN_BRACKET", 85 | "PUN_CLOSE_BRACKET", 86 | "PUN_COLON", 87 | "PUN_COMMA", 88 | ] 89 | 90 | TOKEN_TYPE: dict[TokenTypesKey, int] = { 91 | "IDENTIFIER": 0, 92 | "STRING": 1, 93 | "NUMBER": 2, 94 | "BOOLEAN": 3, 95 | "NULL": 4, 96 | "PUN_OPEN_BRACE": 5, 97 | "PUN_CLOSE_BRACE": 6, 98 | "PUN_OPEN_BRACKET": 7, 99 | "PUN_CLOSE_BRACKET": 8, 100 | "PUN_COLON": 9, 101 | "PUN_COMMA": 10, 102 | } 103 | 104 | TOKEN_TYPE_MAP: dict[int, TokenTypesKey] = {v: k for k, v in TOKEN_TYPE.items()} 105 | 106 | 107 | class Token(NamedTuple): 108 | """Token representation""" 109 | 110 | tk_type: int 111 | # start and end index of the token in the document 112 | value: tuple[int, int] 113 | 114 | 115 | class TokenResult(NamedTuple): 116 | """Token result""" 117 | 118 | token: Token 119 | idx: int 120 | -------------------------------------------------------------------------------- /src/ujson5/consts.py: -------------------------------------------------------------------------------- 1 | """This module contains constants used by the lexer.""" 2 | 3 | import unicodedata 4 | 5 | PUNCTUATORS = { 6 | "{", 7 | "}", 8 | "[", 9 | "]", 10 | ":", 11 | ",", 12 | } 13 | 14 | 15 | LINE_TERMINATOR_SEQUENCE = { 16 | "\u000a", # 17 | "\u000d", # [lookahead ∉ ] 18 | "\u2028", # 19 | "\u2029", # 20 | "\u000d\u000a", # 21 | } 22 | 23 | ESCAPE_SEQUENCE = { 24 | "'": "\u0027", # Apostrophe 25 | '"': "\u0022", # Quotation mark 26 | "\\": "\u005c", # Reverse solidus 27 | "b": "\u0008", # Backspace 28 | "f": "\u000c", # Form feed 29 | "n": "\u000a", # Line feed 30 | "r": "\u000d", # Carriage return 31 | "t": "\u0009", # Horizontal tab 32 | "v": "\u000b", # Vertical tab 33 | "0": "\u0000", # Null 34 | # https://262.ecma-international.org/5.1/#sec-7.8.4 35 | # even though Solidus is not included in the JSON spec 36 | # it is valid in multiple JSON test suits I found... so I'm including it here 37 | # Examples: 38 | # https://github.com/nst/JSONTestSuite 39 | # https://github.com/miloyip/nativejson-benchmark 40 | "/": "\u002f", # Solidus 41 | } 42 | 43 | 44 | NON_ZERO_DIGITS = set(["1", "2", "3", "4", "5", "6", "7", "8", "9"]) 45 | DIGITS = set(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]) 46 | EXPONENT_INDICATORS = {"e", "E"} 47 | HEX_INDICATORS = {"x", "X"} 48 | SIGN = {"+", "-"} 49 | HEX_DIGITS = set( 50 | [ 51 | "0", 52 | "1", 53 | "2", 54 | "3", 55 | "4", 56 | "5", 57 | "6", 58 | "7", 59 | "8", 60 | "9", 61 | "A", 62 | "B", 63 | "C", 64 | "D", 65 | "E", 66 | "F", 67 | "a", 68 | "b", 69 | "c", 70 | "d", 71 | "e", 72 | "f", 73 | ] 74 | ) 75 | 76 | # defined at https://262.ecma-international.org/5.1/#sec-7.6.1.1 77 | KEYWORDS = { 78 | "break", 79 | "do", 80 | "instanceof", 81 | "typeof", 82 | "case", 83 | "else", 84 | "new", 85 | "var", 86 | "catch", 87 | "finally", 88 | "return", 89 | "void", 90 | "continue", 91 | "for", 92 | "switch", 93 | "while", 94 | "debugger", 95 | "function", 96 | "this", 97 | "with", 98 | "default", 99 | "if", 100 | "throw", 101 | "delete", 102 | "in", 103 | "try", 104 | } 105 | 106 | FUTURE_RESERVED_WORDS = { 107 | "class", 108 | "enum", 109 | "extends", 110 | "super", 111 | "const", 112 | "export", 113 | "import", 114 | "implements", 115 | "let", 116 | "private", 117 | "public", 118 | "yield", 119 | "interface", 120 | "package", 121 | "protected", 122 | "static", 123 | } 124 | 125 | RESERVED_WORDS = KEYWORDS.union(FUTURE_RESERVED_WORDS).union( 126 | { 127 | "null", 128 | "true", 129 | "false", 130 | } 131 | ) 132 | 133 | 134 | # defined at https://262.ecma-international.org/5.1/#sec-7.6 135 | UNICODE_LETTERS = { 136 | chr(i) 137 | for i in range(0x110000) 138 | if unicodedata.category(chr(i)) in {"Lu", "Ll", "Lt", "Lm", "Lo", "Nl"} 139 | } 140 | 141 | UNICODE_COMBINING_MARKS = { 142 | chr(i) for i in range(0x110000) if unicodedata.category(chr(i)) in {"Mn", "Mc"} 143 | } 144 | 145 | UNICODE_DIGITS = { 146 | chr(i) for i in range(0x110000) if unicodedata.category(chr(i)) == "Nd" 147 | } 148 | 149 | UNICODE_CONNECTORS = { 150 | chr(i) 151 | for i in range(0x110000) 152 | if (unicodedata.category(chr(i)) == "Pc" and chr(i) != "_") 153 | } 154 | 155 | ZWNJ = "\u200c" # Zero Width Non-Joiner 156 | ZWJ = "\u200d" # Zero Width Joiner 157 | -------------------------------------------------------------------------------- /tests/test_unit_tests/test_number_lexer.py: -------------------------------------------------------------------------------- 1 | """Tests for the number lexer.""" 2 | 3 | from random import randint 4 | 5 | import pytest 6 | 7 | from ujson5.core import TOKEN_TYPE, JSON5DecodeError 8 | from ujson5.lexer import tokenize_number 9 | 10 | number_valid_examples = [ 11 | "0", 12 | "0", 13 | "3e2", 14 | "0e2", 15 | "123", 16 | "123.456", 17 | ".123", 18 | "0.123", 19 | "99.99e10", 20 | "99.99E+10", 21 | "1.2e-3", 22 | "0.0001", 23 | "123e5", 24 | ".5E10", 25 | "1.2E+0 ", 26 | "123.456e10 ", 27 | ".001", 28 | "123", 29 | "0.456", 30 | "7e10", 31 | "1e0", 32 | "1e+0", 33 | "1e-0", 34 | "1.23e10", 35 | "1.23e+10", 36 | "1.23e-10", 37 | "12345678901234567890", 38 | "1.2345678901234567890e+20", 39 | "0x0", 40 | "0x1", 41 | "0x123ABC", 42 | "0XABCDEF", 43 | "-123", 44 | "-123.456", 45 | "+0", 46 | "-0", 47 | "+.123", 48 | "-.434", 49 | "2323.", 50 | ] 51 | 52 | number_valid_constants = [ 53 | "Infinity", 54 | "+Infinity", 55 | "-Infinity", 56 | "NaN", 57 | "+NaN", 58 | "-NaN", 59 | ] 60 | 61 | number_valid_example_upper = [eg.upper() for eg in number_valid_examples] 62 | 63 | number_valid_examples_spaces = [ 64 | f"{eg}{' ' * randint(1, 10)}" 65 | for eg in number_valid_examples + number_valid_example_upper 66 | ] 67 | 68 | number_valid_examples_spaces_entry = [ 69 | f"{eg}{' ' * randint(0, 10)},{' ' * randint(0, 10)}" 70 | for eg in number_valid_examples_spaces + number_valid_example_upper 71 | ] 72 | 73 | 74 | number_invalid_examples = [ 75 | "", 76 | " ", 77 | "-", 78 | "00", 79 | "0123", 80 | "1.2.3", 81 | "1e", 82 | "1e+", 83 | ".e2", 84 | ". 123", 85 | "4.5e ", 86 | "4.5e+ ", 87 | "5.5.5", 88 | "0d", 89 | "2e9d", 90 | "123a", 91 | "1.2.3", 92 | "1e2e3", 93 | "1..2", 94 | "1.2.3", 95 | "1e+e", 96 | "1e-.", 97 | "0123", 98 | "00.123", 99 | "1e 2", 100 | "123abc", 101 | "1.23e10xyz", 102 | ".", 103 | "e", 104 | "e10", 105 | "1e+", 106 | "1e-", 107 | "+", 108 | "-", 109 | "1ek", 110 | "e", 111 | "E", 112 | "0x", 113 | "0xG", 114 | "0x1.23", 115 | "0Xx", 116 | "Inf", 117 | "+Inf", 118 | "Na", 119 | "-Na", 120 | "infinity", 121 | "InfinityHere", 122 | "NaNHere", 123 | "+InfinityHere", 124 | "-NaNHere", 125 | "InfinitY", 126 | "Nan", 127 | "+InfinitY", 128 | "-Nan", 129 | "nan", 130 | "+infinity", 131 | "-infinity", 132 | "+nan", 133 | "-nan", 134 | "InfinityInfinity", 135 | "NaNNad", 136 | "NaNN", 137 | "++", 138 | "- -", 139 | ] 140 | 141 | 142 | @pytest.mark.parametrize( 143 | "text_number", 144 | number_valid_examples 145 | + number_valid_constants 146 | + number_valid_example_upper 147 | + number_valid_examples_spaces 148 | + number_valid_examples_spaces_entry, 149 | ) 150 | def test_valid_numbers(text_number: str) -> None: 151 | """Test valid numbers.""" 152 | result = tokenize_number(buffer=text_number, idx=0) 153 | assert result.token is not None 154 | assert result.token.tk_type == TOKEN_TYPE["NUMBER"] 155 | start, end = result.token.value 156 | if "," in text_number: 157 | assert text_number[start:end] == text_number.strip()[:-1].strip() 158 | else: 159 | assert text_number[start:end] == text_number.strip() 160 | 161 | 162 | @pytest.mark.parametrize("text_number", number_invalid_examples) 163 | def test_invalid_invalid_numbers(text_number: str) -> None: 164 | """Test invalid numbers.""" 165 | with pytest.raises(JSON5DecodeError): 166 | tokenize_number(buffer=text_number, idx=0) 167 | --------------------------------------------------------------------------------