typia 13.1.1 → 13.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/lib/_virtual/_rolldown/runtime.mjs +1 -5
- package/lib/executable/FileSystemIdentity.d.ts +21 -0
- package/lib/executable/FileSystemIdentity.js +183 -0
- package/lib/executable/FileSystemIdentity.js.map +1 -0
- package/lib/executable/FileSystemIdentity.mjs +129 -0
- package/lib/executable/FileSystemIdentity.mjs.map +1 -0
- package/lib/executable/TypiaGenerateWizard.js +264 -104
- package/lib/executable/TypiaGenerateWizard.js.map +1 -1
- package/lib/executable/TypiaGenerateWizard.mjs +233 -93
- package/lib/executable/TypiaGenerateWizard.mjs.map +1 -1
- package/lib/functional.d.ts +15 -12
- package/lib/functional.js.map +1 -1
- package/lib/functional.mjs.map +1 -1
- package/lib/internal/_ProtobufReader.d.ts +17 -0
- package/lib/internal/_ProtobufReader.js +117 -45
- package/lib/internal/_ProtobufReader.js.map +1 -1
- package/lib/internal/_ProtobufReader.mjs +108 -39
- package/lib/internal/_ProtobufReader.mjs.map +1 -1
- package/lib/internal/_createStandardSchema.js +18 -1
- package/lib/internal/_createStandardSchema.js.map +1 -1
- package/lib/internal/_createStandardSchema.mjs +12 -1
- package/lib/internal/_createStandardSchema.mjs.map +1 -1
- package/lib/internal/_decimal.d.ts +14 -0
- package/lib/internal/_decimal.js +61 -0
- package/lib/internal/_decimal.js.map +1 -0
- package/lib/internal/_decimal.mjs +49 -0
- package/lib/internal/_decimal.mjs.map +1 -0
- package/lib/internal/_httpQueryParseURLSearchParams.js +23 -2
- package/lib/internal/_httpQueryParseURLSearchParams.js.map +1 -1
- package/lib/internal/_httpQueryParseURLSearchParams.mjs +20 -2
- package/lib/internal/_httpQueryParseURLSearchParams.mjs.map +1 -1
- package/lib/internal/_isFormatByte.js +2 -5
- package/lib/internal/_isFormatByte.js.map +1 -1
- package/lib/internal/_isFormatByte.mjs +2 -5
- package/lib/internal/_isFormatByte.mjs.map +1 -1
- package/lib/internal/_isFormatDate.js +15 -2
- package/lib/internal/_isFormatDate.js.map +1 -1
- package/lib/internal/_isFormatDate.mjs +22 -2
- package/lib/internal/_isFormatDate.mjs.map +1 -1
- package/lib/internal/_isFormatDateTime.js +21 -2
- package/lib/internal/_isFormatDateTime.js.map +1 -1
- package/lib/internal/_isFormatDateTime.mjs +13 -2
- package/lib/internal/_isFormatDateTime.mjs.map +1 -1
- package/lib/internal/_isFormatIri.js +3 -2
- package/lib/internal/_isFormatIri.js.map +1 -1
- package/lib/internal/_isFormatIri.mjs +3 -2
- package/lib/internal/_isFormatIri.mjs.map +1 -1
- package/lib/internal/_isFormatIriReference.js +10 -2
- package/lib/internal/_isFormatIriReference.js.map +1 -1
- package/lib/internal/_isFormatIriReference.mjs +9 -2
- package/lib/internal/_isFormatIriReference.mjs.map +1 -1
- package/lib/internal/_isFormatUriReference.js +1 -1
- package/lib/internal/_isFormatUriReference.js.map +1 -1
- package/lib/internal/_isFormatUriReference.mjs +1 -1
- package/lib/internal/_isFormatUriReference.mjs.map +1 -1
- package/lib/internal/_isMultipleOf.d.ts +1 -0
- package/lib/internal/_isMultipleOf.js +13 -0
- package/lib/internal/_isMultipleOf.js.map +1 -0
- package/lib/internal/_isMultipleOf.mjs +12 -0
- package/lib/internal/_isMultipleOf.mjs.map +1 -0
- package/lib/internal/_isTypeFloat.js +1 -1
- package/lib/internal/_isTypeFloat.js.map +1 -1
- package/lib/internal/_isTypeFloat.mjs +1 -1
- package/lib/internal/_isTypeFloat.mjs.map +1 -1
- package/lib/internal/_isTypeInt64.js +1 -0
- package/lib/internal/_isTypeInt64.js.map +1 -1
- package/lib/internal/_isTypeInt64.mjs.map +1 -1
- package/lib/internal/_isTypeInt64Bigint.d.ts +1 -0
- package/lib/internal/_isTypeInt64Bigint.js +15 -0
- package/lib/internal/_isTypeInt64Bigint.js.map +1 -0
- package/lib/internal/_isTypeInt64Bigint.mjs +8 -0
- package/lib/internal/_isTypeInt64Bigint.mjs.map +1 -0
- package/lib/internal/_isTypeUint64.js +1 -0
- package/lib/internal/_isTypeUint64.js.map +1 -1
- package/lib/internal/_isTypeUint64.mjs.map +1 -1
- package/lib/internal/_isTypeUint64Bigint.d.ts +1 -0
- package/lib/internal/_isTypeUint64Bigint.js +10 -0
- package/lib/internal/_isTypeUint64Bigint.js.map +1 -0
- package/lib/internal/_isTypeUint64Bigint.mjs +8 -0
- package/lib/internal/_isTypeUint64Bigint.mjs.map +1 -0
- package/lib/internal/_isUniqueItems.js +96 -109
- package/lib/internal/_isUniqueItems.js.map +1 -1
- package/lib/internal/_isUniqueItems.mjs +62 -50
- package/lib/internal/_isUniqueItems.mjs.map +1 -1
- package/lib/internal/_notationAny.js +8 -1
- package/lib/internal/_notationAny.js.map +1 -1
- package/lib/internal/_notationAny.mjs +7 -1
- package/lib/internal/_notationAny.mjs.map +1 -1
- package/lib/internal/_notationAssign.d.ts +1 -0
- package/lib/internal/_notationAssign.js +18 -0
- package/lib/internal/_notationAssign.js.map +1 -0
- package/lib/internal/_notationAssign.mjs +17 -0
- package/lib/internal/_notationAssign.mjs.map +1 -0
- package/lib/internal/_notationCamel.js +30 -9
- package/lib/internal/_notationCamel.js.map +1 -1
- package/lib/internal/_notationCamel.mjs +13 -5
- package/lib/internal/_notationCamel.mjs.map +1 -1
- package/lib/internal/_notationKebab.d.ts +1 -0
- package/lib/internal/_notationKebab.js +15 -0
- package/lib/internal/_notationKebab.js.map +1 -0
- package/lib/internal/_notationKebab.mjs +15 -0
- package/lib/internal/_notationKebab.mjs.map +1 -0
- package/lib/internal/_notationKeyCollision.d.ts +1 -0
- package/lib/internal/_notationKeyCollision.js +8 -0
- package/lib/internal/_notationKeyCollision.js.map +1 -0
- package/lib/internal/_notationKeyCollision.mjs +8 -0
- package/lib/internal/_notationKeyCollision.mjs.map +1 -0
- package/lib/internal/_notationPascal.js +20 -5
- package/lib/internal/_notationPascal.js.map +1 -1
- package/lib/internal/_notationPascal.mjs +10 -5
- package/lib/internal/_notationPascal.mjs.map +1 -1
- package/lib/internal/_notationSnake.js +25 -22
- package/lib/internal/_notationSnake.js.map +1 -1
- package/lib/internal/_notationSnake.mjs +11 -11
- package/lib/internal/_notationSnake.mjs.map +1 -1
- package/lib/internal/_plainCloneAny.js +174 -38
- package/lib/internal/_plainCloneAny.js.map +1 -1
- package/lib/internal/_plainCloneAny.mjs +126 -22
- package/lib/internal/_plainCloneAny.mjs.map +1 -1
- package/lib/internal/_randomArray.d.ts +1 -1
- package/lib/internal/_randomArray.js +11 -4
- package/lib/internal/_randomArray.js.map +1 -1
- package/lib/internal/_randomArray.mjs +9 -3
- package/lib/internal/_randomArray.mjs.map +1 -1
- package/lib/internal/_randomFormatByte.d.ts +2 -1
- package/lib/internal/_randomFormatByte.js +2 -1
- package/lib/internal/_randomFormatByte.js.map +1 -1
- package/lib/internal/_randomFormatByte.mjs +2 -1
- package/lib/internal/_randomFormatByte.mjs.map +1 -1
- package/lib/internal/_randomFormatDate.d.ts +2 -0
- package/lib/internal/_randomFormatDate.js +3 -2
- package/lib/internal/_randomFormatDate.js.map +1 -1
- package/lib/internal/_randomFormatDate.mjs +3 -2
- package/lib/internal/_randomFormatDate.mjs.map +1 -1
- package/lib/internal/_randomFormatDatetime.d.ts +2 -0
- package/lib/internal/_randomFormatDatetime.js +3 -2
- package/lib/internal/_randomFormatDatetime.js.map +1 -1
- package/lib/internal/_randomFormatDatetime.mjs +3 -2
- package/lib/internal/_randomFormatDatetime.mjs.map +1 -1
- package/lib/internal/_randomFormatDuration.d.ts +2 -1
- package/lib/internal/_randomFormatDuration.js +3 -2
- package/lib/internal/_randomFormatDuration.js.map +1 -1
- package/lib/internal/_randomFormatDuration.mjs +3 -2
- package/lib/internal/_randomFormatDuration.mjs.map +1 -1
- package/lib/internal/_randomFormatEmail.d.ts +2 -1
- package/lib/internal/_randomFormatEmail.js +8 -1
- package/lib/internal/_randomFormatEmail.js.map +1 -1
- package/lib/internal/_randomFormatEmail.mjs +5 -1
- package/lib/internal/_randomFormatEmail.mjs.map +1 -1
- package/lib/internal/_randomFormatHostname.d.ts +8 -1
- package/lib/internal/_randomFormatHostname.js +45 -2
- package/lib/internal/_randomFormatHostname.js.map +1 -1
- package/lib/internal/_randomFormatHostname.mjs +38 -2
- package/lib/internal/_randomFormatHostname.mjs.map +1 -1
- package/lib/internal/_randomFormatIdnEmail.d.ts +2 -1
- package/lib/internal/_randomFormatIdnEmail.js +16 -2
- package/lib/internal/_randomFormatIdnEmail.js.map +1 -1
- package/lib/internal/_randomFormatIdnEmail.mjs +11 -2
- package/lib/internal/_randomFormatIdnEmail.mjs.map +1 -1
- package/lib/internal/_randomFormatIdnHostname.d.ts +2 -1
- package/lib/internal/_randomFormatIdnHostname.js +26 -1
- package/lib/internal/_randomFormatIdnHostname.js.map +1 -1
- package/lib/internal/_randomFormatIdnHostname.mjs +25 -2
- package/lib/internal/_randomFormatIdnHostname.mjs.map +1 -1
- package/lib/internal/_randomFormatIpv4.d.ts +2 -1
- package/lib/internal/_randomFormatIpv4.js +2 -1
- package/lib/internal/_randomFormatIpv4.js.map +1 -1
- package/lib/internal/_randomFormatIpv4.mjs +2 -1
- package/lib/internal/_randomFormatIpv4.mjs.map +1 -1
- package/lib/internal/_randomFormatIpv6.d.ts +2 -1
- package/lib/internal/_randomFormatIpv6.js +2 -1
- package/lib/internal/_randomFormatIpv6.js.map +1 -1
- package/lib/internal/_randomFormatIpv6.mjs +2 -1
- package/lib/internal/_randomFormatIpv6.mjs.map +1 -1
- package/lib/internal/_randomFormatIri.d.ts +2 -1
- package/lib/internal/_randomFormatIri.js +1 -1
- package/lib/internal/_randomFormatIri.js.map +1 -1
- package/lib/internal/_randomFormatIri.mjs +1 -1
- package/lib/internal/_randomFormatIri.mjs.map +1 -1
- package/lib/internal/_randomFormatIriReference.d.ts +2 -1
- package/lib/internal/_randomFormatIriReference.js +1 -1
- package/lib/internal/_randomFormatIriReference.js.map +1 -1
- package/lib/internal/_randomFormatIriReference.mjs +1 -1
- package/lib/internal/_randomFormatIriReference.mjs.map +1 -1
- package/lib/internal/_randomFormatJsonPointer.d.ts +2 -1
- package/lib/internal/_randomFormatJsonPointer.js +8 -1
- package/lib/internal/_randomFormatJsonPointer.js.map +1 -1
- package/lib/internal/_randomFormatJsonPointer.mjs +5 -1
- package/lib/internal/_randomFormatJsonPointer.mjs.map +1 -1
- package/lib/internal/_randomFormatPassword.d.ts +2 -1
- package/lib/internal/_randomFormatPassword.js +7 -5
- package/lib/internal/_randomFormatPassword.js.map +1 -1
- package/lib/internal/_randomFormatPassword.mjs +5 -1
- package/lib/internal/_randomFormatPassword.mjs.map +1 -1
- package/lib/internal/_randomFormatRegex.d.ts +2 -1
- package/lib/internal/_randomFormatRegex.js +2 -1
- package/lib/internal/_randomFormatRegex.js.map +1 -1
- package/lib/internal/_randomFormatRegex.mjs +2 -1
- package/lib/internal/_randomFormatRegex.mjs.map +1 -1
- package/lib/internal/_randomFormatRelativeJsonPointer.d.ts +2 -1
- package/lib/internal/_randomFormatRelativeJsonPointer.js +3 -2
- package/lib/internal/_randomFormatRelativeJsonPointer.js.map +1 -1
- package/lib/internal/_randomFormatRelativeJsonPointer.mjs +3 -2
- package/lib/internal/_randomFormatRelativeJsonPointer.mjs.map +1 -1
- package/lib/internal/_randomFormatTime.d.ts +2 -1
- package/lib/internal/_randomFormatTime.js +3 -2
- package/lib/internal/_randomFormatTime.js.map +1 -1
- package/lib/internal/_randomFormatTime.mjs +3 -2
- package/lib/internal/_randomFormatTime.mjs.map +1 -1
- package/lib/internal/_randomFormatUri.d.ts +2 -1
- package/lib/internal/_randomFormatUri.js +1 -1
- package/lib/internal/_randomFormatUri.js.map +1 -1
- package/lib/internal/_randomFormatUri.mjs +1 -1
- package/lib/internal/_randomFormatUri.mjs.map +1 -1
- package/lib/internal/_randomFormatUriReference.d.ts +2 -1
- package/lib/internal/_randomFormatUriReference.js +1 -1
- package/lib/internal/_randomFormatUriReference.js.map +1 -1
- package/lib/internal/_randomFormatUriReference.mjs +1 -1
- package/lib/internal/_randomFormatUriReference.mjs.map +1 -1
- package/lib/internal/_randomFormatUriTemplate.d.ts +2 -1
- package/lib/internal/_randomFormatUriTemplate.js +1 -1
- package/lib/internal/_randomFormatUriTemplate.js.map +1 -1
- package/lib/internal/_randomFormatUriTemplate.mjs +1 -1
- package/lib/internal/_randomFormatUriTemplate.mjs.map +1 -1
- package/lib/internal/_randomFormatUrl.d.ts +2 -1
- package/lib/internal/_randomFormatUrl.js +21 -1
- package/lib/internal/_randomFormatUrl.js.map +1 -1
- package/lib/internal/_randomFormatUrl.mjs +18 -1
- package/lib/internal/_randomFormatUrl.mjs.map +1 -1
- package/lib/internal/_randomFormatUuid.d.ts +2 -1
- package/lib/internal/_randomFormatUuid.js +3 -2
- package/lib/internal/_randomFormatUuid.js.map +1 -1
- package/lib/internal/_randomFormatUuid.mjs +3 -2
- package/lib/internal/_randomFormatUuid.mjs.map +1 -1
- package/lib/internal/_randomInteger.js +59 -28
- package/lib/internal/_randomInteger.js.map +1 -1
- package/lib/internal/_randomInteger.mjs +56 -16
- package/lib/internal/_randomInteger.mjs.map +1 -1
- package/lib/internal/_randomMultiple.d.ts +8 -0
- package/lib/internal/_randomMultiple.js +168 -0
- package/lib/internal/_randomMultiple.js.map +1 -0
- package/lib/internal/_randomMultiple.mjs +158 -0
- package/lib/internal/_randomMultiple.mjs.map +1 -0
- package/lib/internal/_randomNumber.js +42 -42
- package/lib/internal/_randomNumber.js.map +1 -1
- package/lib/internal/_randomNumber.mjs +41 -27
- package/lib/internal/_randomNumber.mjs.map +1 -1
- package/lib/internal/_randomPattern.d.ts +2 -1
- package/lib/internal/_randomPattern.js +19 -4
- package/lib/internal/_randomPattern.js.map +1 -1
- package/lib/internal/_randomPattern.mjs +10 -4
- package/lib/internal/_randomPattern.mjs.map +1 -1
- package/lib/internal/_randomStringLength.d.ts +33 -0
- package/lib/internal/_randomStringLength.js +48 -0
- package/lib/internal/_randomStringLength.js.map +1 -0
- package/lib/internal/_randomStringLength.mjs +44 -0
- package/lib/internal/_randomStringLength.mjs.map +1 -0
- package/lib/internal/_stringLength.d.ts +1 -0
- package/lib/internal/_stringLength.js +11 -0
- package/lib/internal/_stringLength.js.map +1 -0
- package/lib/internal/_stringLength.mjs +10 -0
- package/lib/internal/_stringLength.mjs.map +1 -0
- package/lib/internal/_validateReport.js +4 -1
- package/lib/internal/_validateReport.js.map +1 -1
- package/lib/internal/_validateReport.mjs +2 -1
- package/lib/internal/_validateReport.mjs.map +1 -1
- package/lib/internal/private/__notationRename.d.ts +14 -0
- package/lib/internal/private/__notationRename.js +25 -0
- package/lib/internal/private/__notationRename.js.map +1 -0
- package/lib/internal/private/__notationRename.mjs +24 -0
- package/lib/internal/private/__notationRename.mjs.map +1 -0
- package/lib/json.d.ts +2 -2
- package/lib/json.mjs.map +1 -1
- package/lib/module.d.ts +2 -2
- package/lib/module.js.map +1 -1
- package/lib/module.mjs.map +1 -1
- package/lib/notations.d.ts +20 -4
- package/lib/notations.js.map +1 -1
- package/lib/notations.mjs.map +1 -1
- package/native/adapter/plugin_options.go +117 -0
- package/native/adapter/plugin_options_payload_matrix_test.go +181 -0
- package/native/cmd/ttsc-typia/any_array_type_tags_transform_test.go +63 -9
- package/native/cmd/ttsc-typia/assert_guard_factory_contract_test.go +152 -0
- package/native/cmd/ttsc-typia/build.go +81 -64
- package/native/cmd/ttsc-typia/build_no_emit_preserves_analysis_options_test.go +67 -0
- package/native/cmd/ttsc-typia/build_no_emit_transform_diagnostics_test.go +138 -0
- package/native/cmd/ttsc-typia/build_plugin_options_come_from_payload_test.go +48 -0
- package/native/cmd/ttsc-typia/build_transactional_emit_success_test.go +81 -0
- package/native/cmd/ttsc-typia/build_transform_failure_atomicity_test.go +138 -0
- package/native/cmd/ttsc-typia/command_routes_and_diagnostics_coverage_test.go +3 -1
- package/native/cmd/ttsc-typia/compare_less_nan_transform_test.go +98 -0
- package/native/cmd/ttsc-typia/compare_native_object_overmatch_transform_test.go +161 -0
- package/native/cmd/ttsc-typia/compare_nondiscriminable_union_transform_test.go +343 -0
- package/native/cmd/ttsc-typia/compare_union_discrimination_transform_test.go +289 -0
- package/native/cmd/ttsc-typia/escaped_property_key_path_transform_test.go +193 -0
- package/native/cmd/ttsc-typia/finite_option_number_leaf_transform_test.go +240 -0
- package/native/cmd/ttsc-typia/functional_promised_type_transform_test.go +220 -0
- package/native/cmd/ttsc-typia/functional_receiver_transform_test.go +232 -0
- package/native/cmd/ttsc-typia/is_object_function_member_transform_test.go +205 -0
- package/native/cmd/ttsc-typia/json_application_alias_function_validation_transform_test.go +151 -0
- package/native/cmd/ttsc-typia/json_is_stringify_finite_number_transform_test.go +198 -0
- package/native/cmd/ttsc-typia/json_stringify_special_key_transform_test.go +238 -0
- package/native/cmd/ttsc-typia/main_wasm.go +21 -2
- package/native/cmd/ttsc-typia/native_collection_identity_is_transform_test.go +234 -0
- package/native/cmd/ttsc-typia/native_generic_name_guard_is_transform_test.go +194 -0
- package/native/cmd/ttsc-typia/native_name_collision_is_transform_test.go +204 -0
- package/native/cmd/ttsc-typia/non_trailing_rest_tuple_transform_test.go +23 -11
- package/native/cmd/ttsc-typia/notation_dynamic_keys_transform_test.go +286 -0
- package/native/cmd/ttsc-typia/notation_kebab_case_transform_test.go +1 -1
- package/native/cmd/ttsc-typia/notation_literal_collision_transform_test.go +164 -0
- package/native/cmd/ttsc-typia/notation_pascal_case_transform_test.go +230 -0
- package/native/cmd/ttsc-typia/notation_unicode_key_transform_test.go +309 -0
- package/native/cmd/ttsc-typia/pattern_line_terminator_escape_transform_test.go +224 -0
- package/native/cmd/ttsc-typia/plain_prune_union_object_overmatch_transform_test.go +219 -0
- package/native/cmd/ttsc-typia/plugin_options_payload_helpers_test.go +181 -0
- package/native/cmd/ttsc-typia/private_field_filter_is_transform_test.go +278 -0
- package/native/cmd/ttsc-typia/project_catalog_transform_coverage_test.go +73 -27
- package/native/cmd/ttsc-typia/project_dependencies_barrel_reexport_transform_test.go +120 -0
- package/native/cmd/ttsc-typia/project_dependencies_collapsed_alias_transform_test.go +134 -0
- package/native/cmd/ttsc-typia/project_dependencies_custom_lib_name_transform_test.go +135 -0
- package/native/cmd/ttsc-typia/project_dependencies_default_barrel_transform_test.go +114 -0
- package/native/cmd/ttsc-typia/project_dependencies_empty_heritage_transform_test.go +100 -0
- package/native/cmd/ttsc-typia/project_dependencies_envelope_transform_test.go +148 -0
- package/native/cmd/ttsc-typia/project_dependencies_index_signature_alias_transform_test.go +139 -0
- package/native/cmd/ttsc-typia/project_dependencies_local_reexport_transform_test.go +122 -0
- package/native/cmd/ttsc-typia/project_dependencies_signature_alias_transform_test.go +125 -0
- package/native/cmd/ttsc-typia/project_dependencies_star_barrel_transform_test.go +112 -0
- package/native/cmd/ttsc-typia/project_reference_graph_envelope_transform_test.go +190 -0
- package/native/cmd/ttsc-typia/protobuf_is_encode_finite_number_transform_test.go +98 -0
- package/native/cmd/ttsc-typia/protobuf_sequence_field_numbers_transform_test.go +52 -22
- package/native/cmd/ttsc-typia/symbol_key_member_filter_transform_test.go +279 -0
- package/native/cmd/ttsc-typia/template_interpolation_type_tags_transform_test.go +86 -23
- package/native/cmd/ttsc-typia/template_literal_type_tags_transform_test.go +3 -1
- package/native/cmd/ttsc-typia/transform.go +228 -39
- package/native/cmd/ttsc-typia/{transform_declaration_source_produces_no_js_test.go → transform_declaration_source_produces_no_javascript_test.go} +10 -2
- package/native/cmd/ttsc-typia/transform_fixtures_emit_coverage_test.go +21 -4
- package/native/cmd/ttsc-typia/transform_helpers_test.go +159 -1
- package/native/cmd/ttsc-typia/transform_plugin_options_come_from_payload_test.go +43 -0
- package/native/cmd/ttsc-typia/transform_single_file_failure_atomicity_test.go +114 -0
- package/native/cmd/ttsc-typia/transform_single_file_failure_writes_no_stdout_test.go +43 -0
- package/native/cmd/ttsc-typia/transform_single_file_js_distinguishes_same_basename_sources_test.go +81 -0
- package/native/cmd/ttsc-typia/transform_single_file_js_empty_emit_reports_no_output_test.go +100 -0
- package/native/cmd/ttsc-typia/transform_single_file_js_locates_output_across_layouts_test.go +160 -0
- package/native/cmd/ttsc-typia/transform_single_file_success_publishes_artifact_test.go +54 -0
- package/native/cmd/ttsc-typia/transform_wasm_host_argv_reports_diagnostics_test.go +39 -0
- package/native/cmd/ttsc-typia/tuple_optional_compare_clone_transform_test.go +227 -0
- package/native/core/factories/FormatCheatSheet.go +40 -7
- package/native/core/factories/IdentifierFactory.go +131 -4
- package/native/core/factories/MetadataCommentTagFactory.go +83 -40
- package/native/core/factories/MetadataTypeTagFactory.go +13 -1
- package/native/core/factories/NumericRangeFactory.go +60 -17
- package/native/core/factories/ProtobufFactory.go +7 -4
- package/native/core/factories/factory_utility_coverage_test.go +8 -2
- package/native/core/factories/format_alias_resolves_to_cheat_sheet_test.go +57 -0
- package/native/core/factories/format_alias_table_targets_the_cheat_sheet_test.go +44 -0
- package/native/core/factories/identifier_factory_postfix_escapes_every_key_test.go +147 -0
- package/native/core/factories/identifier_factory_postfix_survives_every_code_point_test.go +86 -0
- package/native/core/factories/internal/metadata/MetadataHelper.go +60 -6
- package/native/core/factories/internal/metadata/emplace_metadata_object.go +116 -8
- package/native/core/factories/internal/metadata/iterate_metadata.go +6 -0
- package/native/core/factories/internal/metadata/iterate_metadata_function.go +4 -11
- package/native/core/factories/internal/metadata/iterate_metadata_intersection.go +8 -6
- package/native/core/factories/internal/metadata/iterate_metadata_map.go +9 -0
- package/native/core/factories/internal/metadata/iterate_metadata_native.go +27 -2
- package/native/core/factories/internal/metadata/iterate_metadata_set.go +9 -0
- package/native/core/factories/internal/metadata/type_arguments_precondition_test.go +70 -0
- package/native/core/factories/metadata_comment_tag_factory_coverage_test.go +39 -0
- package/native/core/factories/metadata_comment_tag_factory_exclusivity_matches_interface_test.go +84 -0
- package/native/core/factories/metadata_type_tag_factory_accepts_legal_tag_combinations_test.go +60 -0
- package/native/core/factories/metadata_type_tag_factory_declarations_test.go +86 -0
- package/native/core/factories/metadata_type_tag_factory_keeps_bool_form_exclusivity_test.go +38 -0
- package/native/core/factories/metadata_type_tag_factory_rejects_cross_kind_exclusive_tags_test.go +65 -0
- package/native/core/factories/metadata_type_tag_factory_rejects_duplicated_array_form_tags_test.go +41 -0
- package/native/core/factories/numeric_range_factory_enforces_64bit_bounds_test.go +69 -0
- package/native/core/factories/protobuf_recovery_ownership_test.go +64 -0
- package/native/core/programmers/IsProgrammer.go +15 -1
- package/native/core/programmers/RandomProgrammer.go +51 -14
- package/native/core/programmers/compare/CompareEqualProgrammer.go +393 -5
- package/native/core/programmers/compare/CompareLessProgrammer.go +4 -2
- package/native/core/programmers/functional/FunctionalAssertFunctionProgrammer.go +4 -6
- package/native/core/programmers/functional/FunctionalAssertParametersProgrammer.go +5 -13
- package/native/core/programmers/functional/FunctionalAssertReturnProgrammer.go +6 -14
- package/native/core/programmers/functional/FunctionalIsFunctionProgrammer.go +4 -6
- package/native/core/programmers/functional/FunctionalIsParametersProgrammer.go +49 -14
- package/native/core/programmers/functional/FunctionalIsReturnProgrammer.go +5 -13
- package/native/core/programmers/functional/FunctionalValidateFunctionProgrammer.go +4 -6
- package/native/core/programmers/functional/FunctionalValidateParametersProgrammer.go +5 -13
- package/native/core/programmers/functional/FunctionalValidateReturnProgrammer.go +5 -13
- package/native/core/programmers/functional/internal/FunctionalGeneralProgrammer.go +4 -17
- package/native/core/programmers/helpers/CloneJoiner.go +32 -0
- package/native/core/programmers/helpers/NotationJoiner.go +86 -28
- package/native/core/programmers/helpers/StringifyJoinder.go +32 -1
- package/native/core/programmers/helpers/UnionExplorer.go +203 -61
- package/native/core/programmers/helpers/joiner_branch_coverage_test.go +5 -3
- package/native/core/programmers/helpers/union_explorer_coverage_test.go +1 -1
- package/native/core/programmers/internal/CheckerProgrammer.go +100 -48
- package/native/core/programmers/iterate/check_template.go +344 -32
- package/native/core/programmers/iterate/json_schema_discriminator.go +36 -10
- package/native/core/programmers/iterate/json_schema_discriminator_declaration_syntax_test.go +205 -0
- package/native/core/programmers/iterate/openapi_v3_downgrader.go +641 -0
- package/native/core/programmers/iterate/openapi_v3_downgrader_boolean_default_test.go +95 -0
- package/native/core/programmers/iterate/openapi_v3_downgrader_test.go +123 -0
- package/native/core/programmers/iterate/template_interpolation_tags_test.go +40 -8
- package/native/core/programmers/iterate/template_runtime_pattern.go +52 -7
- package/native/core/programmers/json/JsonApplicationProgrammer.go +45 -11
- package/native/core/programmers/json/JsonSchemasProgrammer.go +12 -2
- package/native/core/programmers/llm/LlmApplicationProgrammer.go +12 -10
- package/native/core/programmers/llm/LlmSchemaProgrammer.go +23 -6
- package/native/core/programmers/llm/llm_reference_codec_test.go +24 -0
- package/native/core/programmers/notations/NotationGeneralProgrammer.go +183 -67
- package/native/core/programmers/notations/notation_general_helpers_test.go +1 -3
- package/native/core/programmers/notations/notation_general_programmer_pascal_multiword_test.go +72 -0
- package/native/core/programmers/notations/notation_general_programmer_underscore_boundary_test.go +68 -0
- package/native/core/programmers/plain/PlainClassifyProgrammer.go +23 -15
- package/native/core/programmers/plain/PlainCloneProgrammer.go +20 -7
- package/native/core/programmers/plain/PlainPruneProgrammer.go +19 -5
- package/native/core/programmers/plain/plain_tuple_seed_recovery_ownership_test.go +25 -0
- package/native/core/programmers/protobuf/ProtobufDecodeProgrammer.go +37 -28
- package/native/core/programmers/protobuf/ProtobufMessageProgrammer.go +40 -21
- package/native/core/programmers/protobuf/protobuf_programmer_helper_coverage_test.go +26 -0
- package/native/core/programmers/random_programmer_length_argument_test.go +53 -0
- package/native/core/schemas/metadata/MetadataCollection.go +270 -20
- package/native/core/schemas/metadata/MetadataDependency.go +388 -0
- package/native/core/schemas/metadata/MetadataObjectType.go +17 -4
- package/native/core/schemas/metadata/metadata_collection_generic_argument_dot_test.go +122 -0
- package/native/core/schemas/metadata/metadata_collection_name_allocation_test.go +147 -0
- package/native/core/schemas/metadata/metadata_collection_openapi_name_cascade_test.go +55 -0
- package/native/core/schemas/metadata/metadata_collection_openapi_name_test.go +68 -0
- package/native/core/utils/PatternUtil.go +13 -0
- package/native/core/utils/PromiseTypeFactory.go +59 -0
- package/native/core/utils/ProtobufNameEncoder.go +8 -0
- package/native/core/utils/promise_type_factory_semantics_test.go +118 -0
- package/native/go.mod +9 -1
- package/native/transform/CallExpressionTransformer.go +12 -0
- package/native/transform/features/json/JsonApplicationTransformer.go +1 -1
- package/native/transform/features/json/JsonSchemaTransformer.go +1 -1
- package/native/transform/features/json/JsonSchemasTransformer.go +5 -4
- package/package.json +16 -4
- package/src/executable/FileSystemIdentity.ts +189 -0
- package/src/executable/TypiaGenerateWizard.ts +377 -110
- package/src/functional.ts +30 -60
- package/src/internal/_ProtobufReader.ts +129 -43
- package/src/internal/_createStandardSchema.ts +15 -1
- package/src/internal/_decimal.ts +69 -0
- package/src/internal/_httpQueryParseURLSearchParams.ts +24 -2
- package/src/internal/_isFormatByte.ts +2 -5
- package/src/internal/_isFormatDate.ts +15 -2
- package/src/internal/_isFormatDateTime.ts +28 -2
- package/src/internal/_isFormatIri.ts +5 -2
- package/src/internal/_isFormatIriReference.ts +11 -3
- package/src/internal/_isFormatUriReference.ts +1 -1
- package/src/internal/_isMultipleOf.ts +8 -0
- package/src/internal/_isTypeFloat.ts +1 -1
- package/src/internal/_isTypeInt64.ts +1 -0
- package/src/internal/_isTypeInt64Bigint.ts +12 -0
- package/src/internal/_isTypeUint64.ts +1 -0
- package/src/internal/_isTypeUint64Bigint.ts +7 -0
- package/src/internal/_isUniqueItems.ts +134 -132
- package/src/internal/_notationAny.ts +9 -4
- package/src/internal/_notationAssign.ts +20 -0
- package/src/internal/_notationCamel.ts +31 -10
- package/src/internal/_notationKebab.ts +11 -0
- package/src/internal/_notationKeyCollision.ts +9 -0
- package/src/internal/_notationPascal.ts +19 -6
- package/src/internal/_notationSnake.ts +24 -21
- package/src/internal/_plainCloneAny.ts +208 -33
- package/src/internal/_randomArray.ts +13 -4
- package/src/internal/_randomFormatByte.ts +4 -1
- package/src/internal/_randomFormatDate.ts +17 -12
- package/src/internal/_randomFormatDatetime.ts +15 -10
- package/src/internal/_randomFormatDuration.ts +16 -14
- package/src/internal/_randomFormatEmail.ts +8 -2
- package/src/internal/_randomFormatHostname.ts +48 -1
- package/src/internal/_randomFormatIdnEmail.ts +18 -2
- package/src/internal/_randomFormatIdnHostname.ts +34 -2
- package/src/internal/_randomFormatIpv4.ts +3 -2
- package/src/internal/_randomFormatIpv6.ts +3 -2
- package/src/internal/_randomFormatIri.ts +3 -1
- package/src/internal/_randomFormatIriReference.ts +3 -1
- package/src/internal/_randomFormatJsonPointer.ts +8 -2
- package/src/internal/_randomFormatPassword.ts +11 -6
- package/src/internal/_randomFormatRegex.ts +4 -1
- package/src/internal/_randomFormatRelativeJsonPointer.ts +13 -6
- package/src/internal/_randomFormatTime.ts +13 -10
- package/src/internal/_randomFormatUri.ts +3 -1
- package/src/internal/_randomFormatUriReference.ts +3 -1
- package/src/internal/_randomFormatUriTemplate.ts +3 -1
- package/src/internal/_randomFormatUrl.ts +25 -2
- package/src/internal/_randomFormatUuid.ts +10 -6
- package/src/internal/_randomInteger.ts +87 -40
- package/src/internal/_randomMultiple.ts +245 -0
- package/src/internal/_randomNumber.ts +72 -55
- package/src/internal/_randomPattern.ts +26 -4
- package/src/internal/_randomStringLength.ts +72 -0
- package/src/internal/_stringLength.ts +5 -0
- package/src/internal/_validateReport.ts +5 -1
- package/src/internal/private/__notationRename.ts +24 -0
- package/src/json.ts +2 -2
- package/src/module.ts +4 -6
- package/src/notations.ts +20 -4
- package/lib/internal/private/__notationCapitalize.d.ts +0 -1
- package/lib/internal/private/__notationCapitalize.js +0 -6
- package/lib/internal/private/__notationCapitalize.js.map +0 -1
- package/lib/internal/private/__notationCapitalize.mjs +0 -6
- package/lib/internal/private/__notationCapitalize.mjs.map +0 -1
- package/lib/internal/private/__notationUnsnake.d.ts +0 -4
- package/lib/internal/private/__notationUnsnake.js +0 -26
- package/lib/internal/private/__notationUnsnake.js.map +0 -1
- package/lib/internal/private/__notationUnsnake.mjs +0 -15
- package/lib/internal/private/__notationUnsnake.mjs.map +0 -1
- package/native/cmd/ttsc-typia/plugin_options_missing_config_test.go +0 -26
- package/native/cmd/ttsc-typia/plugin_options_undefined_false_test.go +0 -36
- package/src/internal/private/__notationCapitalize.ts +0 -2
- package/src/internal/private/__notationUnsnake.ts +0 -24
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"os/exec"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"strings"
|
|
8
|
+
"testing"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// TestNotationUnicodeKeyTransform verifies the notation emit keeps a non-ASCII
|
|
12
|
+
// key intact and agrees with the runtime helper.
|
|
13
|
+
//
|
|
14
|
+
// Issue #2227: the emit computed each renamed key by slicing one *byte*
|
|
15
|
+
// (`value[:1]`) before case-converting it, so a multi-byte rune's lead byte was
|
|
16
|
+
// handed to the case operation on its own, could not be decoded, and came back
|
|
17
|
+
// as U+FFFD — `typia.notations.createPascal<{ "École": number }>()` emitted the
|
|
18
|
+
// key `"��cole"`. The static path corrupted the key while the dynamic
|
|
19
|
+
// (index-signature) path, which calls the runtime `_notationPascal`, did not, so
|
|
20
|
+
// one object could carry two different renamings of the same character and the
|
|
21
|
+
// emitted key did not match its declared `CamelCase<T>` / `PascalCase<T>` type.
|
|
22
|
+
//
|
|
23
|
+
// The same fix covers the second half of the divergence: JavaScript performs
|
|
24
|
+
// Unicode *full* case conversion while Go's `strings.ToUpper`/`ToLower` perform
|
|
25
|
+
// the *simple* per-rune mapping, so the emit also disagreed with the runtime on
|
|
26
|
+
// `ß` -> `SS`, `İ` -> `i` + U+0307, and the word-final sigma `ΑΣ` -> `ας`. That
|
|
27
|
+
// half reached `snake`/`kebab` too, which never sliced a byte.
|
|
28
|
+
//
|
|
29
|
+
// Every key and every expectation below is written with `\uXXXX` escapes so the
|
|
30
|
+
// fixture cannot be silently renormalized (NFC/NFD) by an editor, and so the
|
|
31
|
+
// combining-mark and surrogate-pair cases stay exactly what they claim to be.
|
|
32
|
+
//
|
|
33
|
+
// 1. Transform a fixture whose keys cover a multi-byte first character, a
|
|
34
|
+
// multi-byte character right after an underscore, a key that is a single
|
|
35
|
+
// multi-byte character, a combining mark (NFD), a surrogate pair, and the
|
|
36
|
+
// case-folding-sensitive `İ`, `ß`, and word-final sigma — plus two ASCII
|
|
37
|
+
// keys as a regression anchor.
|
|
38
|
+
// 2. Require the emitted JavaScript to carry no U+FFFD at all.
|
|
39
|
+
// 3. Execute each statically emitted converter and assert its key-to-value map
|
|
40
|
+
// equals the expectation derived from JavaScript's own case semantics.
|
|
41
|
+
// 4. Execute the dynamic `Record` converter, which routes through the runtime
|
|
42
|
+
// `_notation*` helper, over the same keys and require an identical map, so
|
|
43
|
+
// the compile-time emit and the runtime helper are proven equal per key.
|
|
44
|
+
func TestNotationUnicodeKeyTransform(t *testing.T) {
|
|
45
|
+
project := notationUnicodeKeyProject(t)
|
|
46
|
+
out, errText, code := ttscTypiaTestCapture(func() int {
|
|
47
|
+
return runTransform([]string{
|
|
48
|
+
"--cwd", project,
|
|
49
|
+
"--tsconfig", "tsconfig.json",
|
|
50
|
+
"--file", "src/main.ts",
|
|
51
|
+
"--output", "js",
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
if code != 0 {
|
|
55
|
+
t.Fatalf("unicode notation transform failed: code=%d stderr=\n%s", code, errText)
|
|
56
|
+
}
|
|
57
|
+
// The printer escapes every non-ASCII code unit, so a corrupted key reaches
|
|
58
|
+
// the output as the escape text rather than as the replacement rune itself.
|
|
59
|
+
// Both forms are rejected; checking only the rune would never fire.
|
|
60
|
+
if strings.Contains(out, `\uFFFD`) || strings.ContainsRune(out, '�') {
|
|
61
|
+
t.Fatalf("emitted converter must not contain U+FFFD; a key was corrupted by byte slicing:\n%s", out)
|
|
62
|
+
}
|
|
63
|
+
// Pin the exact emitted assignments for the witnesses of each half of the
|
|
64
|
+
// defect: the multi-byte first character and the post-underscore segment that
|
|
65
|
+
// byte slicing destroyed, plus the two characters that the simple per-rune
|
|
66
|
+
// case mapping got wrong. The printer escapes every non-ASCII code unit, so
|
|
67
|
+
// these are the literal bytes of the emitted JavaScript.
|
|
68
|
+
for _, assignment := range []string{
|
|
69
|
+
`["\u00E9cole"]: input["\u00C9cole"]`,
|
|
70
|
+
`["Key\u00D6lig"]: input["key_\u00D6lig"]`,
|
|
71
|
+
`["SS"]: input["\u00DF"]`,
|
|
72
|
+
`["i\u0307stanbul"]: input["\u0130stanbul"]`,
|
|
73
|
+
} {
|
|
74
|
+
if !strings.Contains(out, assignment) {
|
|
75
|
+
t.Fatalf("emitted converter should contain the assignment %s:\n%s", assignment, out)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
notationUnicodeKeyRunRuntimeCases(t, project, out)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
func notationUnicodeKeyProject(t *testing.T) string {
|
|
82
|
+
t.Helper()
|
|
83
|
+
root := ttscTypiaTestRepoRoot(t)
|
|
84
|
+
base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
|
|
85
|
+
if err := os.MkdirAll(base, 0o755); err != nil {
|
|
86
|
+
t.Fatalf("mkdir temp base: %v", err)
|
|
87
|
+
}
|
|
88
|
+
dir, err := os.MkdirTemp(base, "notation-unicode-")
|
|
89
|
+
if err != nil {
|
|
90
|
+
t.Fatalf("create temp fixture: %v", err)
|
|
91
|
+
}
|
|
92
|
+
t.Cleanup(func() {
|
|
93
|
+
_ = os.RemoveAll(dir)
|
|
94
|
+
})
|
|
95
|
+
src := filepath.Join(dir, "src")
|
|
96
|
+
if err := os.MkdirAll(src, 0o755); err != nil {
|
|
97
|
+
t.Fatalf("mkdir fixture src: %v", err)
|
|
98
|
+
}
|
|
99
|
+
if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(notationUnicodeKeyTSConfig), 0o644); err != nil {
|
|
100
|
+
t.Fatalf("write tsconfig: %v", err)
|
|
101
|
+
}
|
|
102
|
+
if err := os.WriteFile(filepath.Join(src, "main.ts"), []byte(notationUnicodeKeySource), 0o644); err != nil {
|
|
103
|
+
t.Fatalf("write source: %v", err)
|
|
104
|
+
}
|
|
105
|
+
return dir
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
func notationUnicodeKeyRunRuntimeCases(t *testing.T, project string, js string) {
|
|
109
|
+
t.Helper()
|
|
110
|
+
node, err := exec.LookPath("node")
|
|
111
|
+
if err != nil {
|
|
112
|
+
t.Skip("node executable not found")
|
|
113
|
+
}
|
|
114
|
+
runtimeDir := filepath.Join(project, "runtime")
|
|
115
|
+
if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
|
|
116
|
+
t.Fatalf("mkdir runtime dir: %v", err)
|
|
117
|
+
}
|
|
118
|
+
ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
|
|
119
|
+
runtimeJS := ttscTypiaTestRewriteCommonJS(t, js)
|
|
120
|
+
if err := os.WriteFile(filepath.Join(runtimeDir, "main.cjs"), []byte(runtimeJS), 0o644); err != nil {
|
|
121
|
+
t.Fatalf("write runtime module: %v", err)
|
|
122
|
+
}
|
|
123
|
+
runner := filepath.Join(runtimeDir, "run.cjs")
|
|
124
|
+
if err := os.WriteFile(runner, []byte(notationUnicodeKeyRuntimeRunner), 0o644); err != nil {
|
|
125
|
+
t.Fatalf("write runtime runner: %v", err)
|
|
126
|
+
}
|
|
127
|
+
cmd := exec.Command(node, runner)
|
|
128
|
+
cmd.Dir = runtimeDir
|
|
129
|
+
output, err := cmd.CombinedOutput()
|
|
130
|
+
if err != nil {
|
|
131
|
+
t.Fatalf("unicode notation runtime cases failed: %v\n%s", err, output)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const notationUnicodeKeyTSConfig = `{
|
|
136
|
+
"compilerOptions": {
|
|
137
|
+
"target": "ES2022",
|
|
138
|
+
"module": "commonjs",
|
|
139
|
+
"moduleResolution": "bundler",
|
|
140
|
+
"ignoreDeprecations": "6.0",
|
|
141
|
+
"types": ["*"],
|
|
142
|
+
"esModuleInterop": true,
|
|
143
|
+
"strict": true,
|
|
144
|
+
"skipLibCheck": true
|
|
145
|
+
},
|
|
146
|
+
"include": ["src"]
|
|
147
|
+
}
|
|
148
|
+
`
|
|
149
|
+
|
|
150
|
+
const notationUnicodeKeySource = `import typia from "typia";
|
|
151
|
+
|
|
152
|
+
interface SourceRecord {
|
|
153
|
+
"\u00C9cole": number;
|
|
154
|
+
"\u00F6lwert": number;
|
|
155
|
+
"\u65E5\u672C\u8A9E": number;
|
|
156
|
+
"key_\u00D6lig": number;
|
|
157
|
+
"\u00D6": number;
|
|
158
|
+
"\u0130stanbul": number;
|
|
159
|
+
"\u00DF": number;
|
|
160
|
+
"\uD801\uDC28test": number;
|
|
161
|
+
"\u0391\u03A3_\u0391\u03A3": number;
|
|
162
|
+
"e\u0301cole": number;
|
|
163
|
+
"\u00FCber_Stra\u00DFe": number;
|
|
164
|
+
MAX_COUNT: number;
|
|
165
|
+
fooBar: number;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
type DynamicRecord = Record<string, number>;
|
|
169
|
+
|
|
170
|
+
export const toCamel = typia.notations.createCamel<SourceRecord>();
|
|
171
|
+
export const toPascal = typia.notations.createPascal<SourceRecord>();
|
|
172
|
+
export const toSnake = typia.notations.createSnake<SourceRecord>();
|
|
173
|
+
export const toKebab = typia.notations.createKebab<SourceRecord>();
|
|
174
|
+
|
|
175
|
+
export const toCamelDynamic = typia.notations.createCamel<DynamicRecord>();
|
|
176
|
+
export const toPascalDynamic = typia.notations.createPascal<DynamicRecord>();
|
|
177
|
+
export const toSnakeDynamic = typia.notations.createSnake<DynamicRecord>();
|
|
178
|
+
export const toKebabDynamic = typia.notations.createKebab<DynamicRecord>();
|
|
179
|
+
`
|
|
180
|
+
|
|
181
|
+
const notationUnicodeKeyRuntimeRunner = `const mod = require("./main.cjs");
|
|
182
|
+
|
|
183
|
+
// Every source key carries a distinct value, so comparing the whole
|
|
184
|
+
// key-to-value map proves the per-key renaming rather than just the key set.
|
|
185
|
+
const input = {
|
|
186
|
+
["\u00C9cole"]: 1,
|
|
187
|
+
["\u00F6lwert"]: 2,
|
|
188
|
+
["\u65E5\u672C\u8A9E"]: 3,
|
|
189
|
+
["key_\u00D6lig"]: 4,
|
|
190
|
+
["\u00D6"]: 5,
|
|
191
|
+
["\u0130stanbul"]: 6,
|
|
192
|
+
["\u00DF"]: 7,
|
|
193
|
+
["\uD801\uDC28test"]: 8,
|
|
194
|
+
["\u0391\u03A3_\u0391\u03A3"]: 9,
|
|
195
|
+
["e\u0301cole"]: 10,
|
|
196
|
+
["\u00FCber_Stra\u00DFe"]: 11,
|
|
197
|
+
["MAX_COUNT"]: 12,
|
|
198
|
+
["fooBar"]: 13,
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Expectations are JavaScript's own case semantics, not a snapshot of the Go
|
|
202
|
+
// emit: full case conversion (ß -> SS, İ -> i + U+0307, word-final
|
|
203
|
+
// sigma ΑΣ -> ας) and UTF-16 code-unit indexing, under which
|
|
204
|
+
// str[0] of an astral character is an uncased lone surrogate and stays put.
|
|
205
|
+
const expected = {
|
|
206
|
+
camel: {
|
|
207
|
+
["\u00E9cole"]: 1,
|
|
208
|
+
["\u00F6lwert"]: 2,
|
|
209
|
+
["\u65E5\u672C\u8A9E"]: 3,
|
|
210
|
+
["key\u00D6lig"]: 4,
|
|
211
|
+
["\u00F6"]: 5,
|
|
212
|
+
["i\u0307stanbul"]: 6,
|
|
213
|
+
["\u00DF"]: 7,
|
|
214
|
+
["\uD801\uDC28test"]: 8,
|
|
215
|
+
["\u03B1\u03C2\u0391\u03C3"]: 9,
|
|
216
|
+
["e\u0301cole"]: 10,
|
|
217
|
+
["\u00FCberStra\u00DFe"]: 11,
|
|
218
|
+
["maxCount"]: 12,
|
|
219
|
+
["fooBar"]: 13,
|
|
220
|
+
},
|
|
221
|
+
pascal: {
|
|
222
|
+
["\u00C9cole"]: 1,
|
|
223
|
+
["\u00D6lwert"]: 2,
|
|
224
|
+
["\u65E5\u672C\u8A9E"]: 3,
|
|
225
|
+
["Key\u00D6lig"]: 4,
|
|
226
|
+
["\u00D6"]: 5,
|
|
227
|
+
["\u0130stanbul"]: 6,
|
|
228
|
+
["SS"]: 7,
|
|
229
|
+
["\uD801\uDC28test"]: 8,
|
|
230
|
+
["\u0391\u03C3\u0391\u03C3"]: 9,
|
|
231
|
+
["E\u0301cole"]: 10,
|
|
232
|
+
["\u00DCberStra\u00DFe"]: 11,
|
|
233
|
+
["MaxCount"]: 12,
|
|
234
|
+
["FooBar"]: 13,
|
|
235
|
+
},
|
|
236
|
+
snake: {
|
|
237
|
+
["\u00E9cole"]: 1,
|
|
238
|
+
["\u00F6lwert"]: 2,
|
|
239
|
+
["\u65E5\u672C\u8A9E"]: 3,
|
|
240
|
+
["key_\u00F6lig"]: 4,
|
|
241
|
+
["\u00F6"]: 5,
|
|
242
|
+
["i\u0307stanbul"]: 6,
|
|
243
|
+
["\u00DF"]: 7,
|
|
244
|
+
["\uD801\uDC28test"]: 8,
|
|
245
|
+
["\u03B1\u03C2_\u03B1\u03C2"]: 9,
|
|
246
|
+
["e\u0301cole"]: 10,
|
|
247
|
+
["\u00FCber_stra\u00DFe"]: 11,
|
|
248
|
+
["max_count"]: 12,
|
|
249
|
+
["foo_bar"]: 13,
|
|
250
|
+
},
|
|
251
|
+
kebab: {
|
|
252
|
+
["\u00E9cole"]: 1,
|
|
253
|
+
["\u00F6lwert"]: 2,
|
|
254
|
+
["\u65E5\u672C\u8A9E"]: 3,
|
|
255
|
+
["key-\u00F6lig"]: 4,
|
|
256
|
+
["\u00F6"]: 5,
|
|
257
|
+
["i\u0307stanbul"]: 6,
|
|
258
|
+
["\u00DF"]: 7,
|
|
259
|
+
["\uD801\uDC28test"]: 8,
|
|
260
|
+
["\u03B1\u03C2-\u03B1\u03C2"]: 9,
|
|
261
|
+
["e\u0301cole"]: 10,
|
|
262
|
+
["\u00FCber-stra\u00DFe"]: 11,
|
|
263
|
+
["max-count"]: 12,
|
|
264
|
+
["foo-bar"]: 13,
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
const normalize = (object) =>
|
|
269
|
+
JSON.stringify(
|
|
270
|
+
Object.entries(object)
|
|
271
|
+
.map(([key, value]) => [Array.from(key, (c) => c.charCodeAt(0)), value])
|
|
272
|
+
.sort((a, b) => (String(a) < String(b) ? -1 : 1)),
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
const notations = ["camel", "pascal", "snake", "kebab"];
|
|
276
|
+
const capitalize = (name) => name[0].toUpperCase() + name.substring(1);
|
|
277
|
+
|
|
278
|
+
for (const notation of notations) {
|
|
279
|
+
const want = normalize(expected[notation]);
|
|
280
|
+
|
|
281
|
+
// The statically emitted converter: one property assignment per known key.
|
|
282
|
+
const staticResult = mod["to" + capitalize(notation)](input);
|
|
283
|
+
if (normalize(staticResult) !== want) {
|
|
284
|
+
throw new Error(
|
|
285
|
+
"static " + notation + " emit disagreed with JavaScript case semantics:\n" +
|
|
286
|
+
" expected " + want + "\n" +
|
|
287
|
+
" actual " + normalize(staticResult),
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// The dynamic converter: one runtime _notation* call per index-signature key.
|
|
292
|
+
const dynamicResult = mod["to" + capitalize(notation) + "Dynamic"](input);
|
|
293
|
+
if (normalize(dynamicResult) !== normalize(staticResult)) {
|
|
294
|
+
throw new Error(
|
|
295
|
+
"static " + notation + " emit disagreed with the runtime helper:\n" +
|
|
296
|
+
" runtime " + normalize(dynamicResult) + "\n" +
|
|
297
|
+
" emit " + normalize(staticResult),
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
for (const key of Object.keys(staticResult)) {
|
|
302
|
+
if (key.includes("�")) {
|
|
303
|
+
throw new Error(
|
|
304
|
+
"renamed " + notation + " key contains U+FFFD: " + JSON.stringify(key),
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
`
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"os/exec"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"strings"
|
|
8
|
+
"testing"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// TestPatternLineTerminatorEscapeTransform verifies that a line terminator in a
|
|
12
|
+
// structural (template-literal-type or dynamic-key) pattern is escaped before it
|
|
13
|
+
// is spliced into an emitted `RegExp(/.../)` literal.
|
|
14
|
+
//
|
|
15
|
+
// A JavaScript regex literal cannot contain a raw line terminator, so a template
|
|
16
|
+
// literal type or dynamic key whose literal part holds one of the four
|
|
17
|
+
// ECMAScript LineTerminators (LF, CR, U+2028, U+2029) produced an unparsable
|
|
18
|
+
// module while the transform still exited 0 (a false-green). `PatternUtil.Escape`
|
|
19
|
+
// escaped the regex metacharacters but not the line terminators, and it is the
|
|
20
|
+
// single source feeding every regex-literal sink (`check_template`,
|
|
21
|
+
// `stringify_dynamic_properties`, `prune_object_properties`, and the
|
|
22
|
+
// clone/prune/classify/notation joiners), so one fixture that drives `is`,
|
|
23
|
+
// `json.stringify`, `clone`, `prune`, and `notations` over line-terminator
|
|
24
|
+
// patterns exercises them all (#2211).
|
|
25
|
+
//
|
|
26
|
+
// 1. Transform a fixture whose template literal types and Record dynamic keys
|
|
27
|
+
// carry each of the four line terminators, across every affected operation.
|
|
28
|
+
// 2. Assert the transform exits 0 and `node --check` accepts the whole emit as
|
|
29
|
+
// JavaScript -- RED before the fix (raw LF/CR/LS/PS in a regex literal).
|
|
30
|
+
// 3. Execute the emit and assert each `is` predicate matches a
|
|
31
|
+
// line-terminator-containing value and rejects a value that lacks it.
|
|
32
|
+
func TestPatternLineTerminatorEscapeTransform(t *testing.T) {
|
|
33
|
+
project := patternLineTerminatorProject(t)
|
|
34
|
+
js := patternLineTerminatorTransform(t, project)
|
|
35
|
+
// A line-terminator-free template still lowers to its historical pattern, so
|
|
36
|
+
// nothing but the escaped line terminators changes.
|
|
37
|
+
if !strings.Contains(js, "RegExp(/^prefix(.*)postfix$/)") {
|
|
38
|
+
t.Fatalf("line-terminator-free pattern must keep its historical form:\n%s", js)
|
|
39
|
+
}
|
|
40
|
+
patternLineTerminatorCheckSyntax(t, project, js)
|
|
41
|
+
patternLineTerminatorRunRuntimeCases(t, project, js)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func patternLineTerminatorProject(t *testing.T) string {
|
|
45
|
+
t.Helper()
|
|
46
|
+
root := ttscTypiaTestRepoRoot(t)
|
|
47
|
+
base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
|
|
48
|
+
if err := os.MkdirAll(base, 0o755); err != nil {
|
|
49
|
+
t.Fatalf("mkdir temp base: %v", err)
|
|
50
|
+
}
|
|
51
|
+
dir, err := os.MkdirTemp(base, "pattern-line-terminator-")
|
|
52
|
+
if err != nil {
|
|
53
|
+
t.Fatalf("create temp fixture: %v", err)
|
|
54
|
+
}
|
|
55
|
+
t.Cleanup(func() {
|
|
56
|
+
_ = os.RemoveAll(dir)
|
|
57
|
+
})
|
|
58
|
+
src := filepath.Join(dir, "src")
|
|
59
|
+
if err := os.MkdirAll(src, 0o755); err != nil {
|
|
60
|
+
t.Fatalf("mkdir fixture src: %v", err)
|
|
61
|
+
}
|
|
62
|
+
if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(patternLineTerminatorTSConfig), 0o644); err != nil {
|
|
63
|
+
t.Fatalf("write tsconfig: %v", err)
|
|
64
|
+
}
|
|
65
|
+
if err := os.WriteFile(filepath.Join(src, "main.ts"), []byte(patternLineTerminatorSource), 0o644); err != nil {
|
|
66
|
+
t.Fatalf("write source: %v", err)
|
|
67
|
+
}
|
|
68
|
+
return dir
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func patternLineTerminatorTransform(t *testing.T, project string) string {
|
|
72
|
+
t.Helper()
|
|
73
|
+
out, errText, code := ttscTypiaTestCapture(func() int {
|
|
74
|
+
return runTransform([]string{
|
|
75
|
+
"--cwd", project,
|
|
76
|
+
"--tsconfig", "tsconfig.json",
|
|
77
|
+
"--file", "src/main.ts",
|
|
78
|
+
"--output", "js",
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
if code != 0 {
|
|
82
|
+
t.Fatalf("line terminator pattern transform failed: code=%d stderr=\n%s", code, errText)
|
|
83
|
+
}
|
|
84
|
+
return out
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// patternLineTerminatorCheckSyntax runs node against the emit exactly as it would
|
|
88
|
+
// ship. node --check only parses, so the unresolved typia imports in the
|
|
89
|
+
// untouched output do not matter, which keeps this a check of the real artifact.
|
|
90
|
+
func patternLineTerminatorCheckSyntax(t *testing.T, project string, js string) {
|
|
91
|
+
t.Helper()
|
|
92
|
+
node, err := exec.LookPath("node")
|
|
93
|
+
if err != nil {
|
|
94
|
+
t.Skip("node executable not found")
|
|
95
|
+
}
|
|
96
|
+
emitted := filepath.Join(project, "emitted.cjs")
|
|
97
|
+
if err := os.WriteFile(emitted, []byte(js), 0o644); err != nil {
|
|
98
|
+
t.Fatalf("write emitted module: %v", err)
|
|
99
|
+
}
|
|
100
|
+
if output, err := exec.Command(node, "--check", emitted).CombinedOutput(); err != nil {
|
|
101
|
+
t.Fatalf("emitted module is not valid JavaScript: %v\n%s\n--- emit ---\n%s", err, output, js)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
func patternLineTerminatorRunRuntimeCases(t *testing.T, project string, js string) {
|
|
106
|
+
t.Helper()
|
|
107
|
+
node, err := exec.LookPath("node")
|
|
108
|
+
if err != nil {
|
|
109
|
+
t.Skip("node executable not found")
|
|
110
|
+
}
|
|
111
|
+
runtimeDir := filepath.Join(project, "runtime")
|
|
112
|
+
if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
|
|
113
|
+
t.Fatalf("mkdir runtime dir: %v", err)
|
|
114
|
+
}
|
|
115
|
+
ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
|
|
116
|
+
// json.stringify pulls in _jsonStringifyNumber, which the shared rewrite does
|
|
117
|
+
// not map; stub it locally so the whole module loads. The runner only exercises
|
|
118
|
+
// the `is` predicates, so the stub body is immaterial.
|
|
119
|
+
if err := os.WriteFile(filepath.Join(runtimeDir, "json-stringify-number-stub.cjs"), []byte(patternLineTerminatorNumberStub), 0o644); err != nil {
|
|
120
|
+
t.Fatalf("write json stringify number stub: %v", err)
|
|
121
|
+
}
|
|
122
|
+
runtimeJS := strings.ReplaceAll(js, `require("typia/lib/internal/_jsonStringifyNumber")`, `require("./json-stringify-number-stub.cjs")`)
|
|
123
|
+
runtimeJS = ttscTypiaTestRewriteCommonJS(t, runtimeJS)
|
|
124
|
+
if err := os.WriteFile(filepath.Join(runtimeDir, "main.cjs"), []byte(runtimeJS), 0o644); err != nil {
|
|
125
|
+
t.Fatalf("write runtime module: %v", err)
|
|
126
|
+
}
|
|
127
|
+
runner := filepath.Join(runtimeDir, "run.cjs")
|
|
128
|
+
if err := os.WriteFile(runner, []byte(patternLineTerminatorRuntimeRunner), 0o644); err != nil {
|
|
129
|
+
t.Fatalf("write runtime runner: %v", err)
|
|
130
|
+
}
|
|
131
|
+
cmd := exec.Command(node, runner)
|
|
132
|
+
cmd.Dir = runtimeDir
|
|
133
|
+
if output, err := cmd.CombinedOutput(); err != nil {
|
|
134
|
+
t.Fatalf("line terminator pattern runtime cases failed: %v\n%s", err, output)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const patternLineTerminatorNumberStub = `module.exports._jsonStringifyNumber = (value) => String(value);
|
|
139
|
+
`
|
|
140
|
+
|
|
141
|
+
const patternLineTerminatorTSConfig = `{
|
|
142
|
+
"compilerOptions": {
|
|
143
|
+
"target": "ES2022",
|
|
144
|
+
"module": "commonjs",
|
|
145
|
+
"moduleResolution": "bundler",
|
|
146
|
+
"ignoreDeprecations": "6.0",
|
|
147
|
+
"types": ["*"],
|
|
148
|
+
"esModuleInterop": true,
|
|
149
|
+
"strict": true,
|
|
150
|
+
"skipLibCheck": true
|
|
151
|
+
},
|
|
152
|
+
"include": ["src"]
|
|
153
|
+
}
|
|
154
|
+
`
|
|
155
|
+
|
|
156
|
+
// The template literal types embed the line terminators as TypeScript escapes
|
|
157
|
+
// (backslash n, backslash r, backslash u2028, backslash u2029), which the
|
|
158
|
+
// compiler folds into real line terminator characters in the literal type --
|
|
159
|
+
// the exact trigger.
|
|
160
|
+
const patternLineTerminatorSource = `import typia from "typia";
|
|
161
|
+
|
|
162
|
+
export const isLF = typia.createIs<` + "`a\\n${string}b`" + `>();
|
|
163
|
+
export const isCR = typia.createIs<` + "`a\\r${string}b`" + `>();
|
|
164
|
+
export const isLS = typia.createIs<` + "`a\\u2028${string}b`" + `>();
|
|
165
|
+
export const isPS = typia.createIs<` + "`a\\u2029${string}b`" + `>();
|
|
166
|
+
export const isControl = typia.createIs<` + "`prefix${string}postfix`" + `>();
|
|
167
|
+
|
|
168
|
+
type LFRecord = Record<` + "`a\\n${string}`" + `, number>;
|
|
169
|
+
export const isRecord = typia.createIs<LFRecord>();
|
|
170
|
+
export const stringifyRecord = typia.json.createStringify<LFRecord>();
|
|
171
|
+
export const cloneRecord = typia.plain.createClone<LFRecord>();
|
|
172
|
+
export const pruneRecord = typia.plain.createPrune<LFRecord>();
|
|
173
|
+
export const camelRecord = typia.notations.createCamel<LFRecord>();
|
|
174
|
+
`
|
|
175
|
+
|
|
176
|
+
// Every value's only line terminator is the one the template's literal part
|
|
177
|
+
// pins, so the trailing `(.*)` (dot excludes newlines) still matches the tail.
|
|
178
|
+
// LF/CR go in as JS escapes and U+2028/U+2029 via String.fromCharCode so this
|
|
179
|
+
// source carries no raw line terminator of its own.
|
|
180
|
+
const patternLineTerminatorRuntimeRunner = `const mod = require("./main.cjs");
|
|
181
|
+
|
|
182
|
+
const LS = String.fromCharCode(0x2028);
|
|
183
|
+
const PS = String.fromCharCode(0x2029);
|
|
184
|
+
const cases = [
|
|
185
|
+
["isLF", "a\nZZb", "aZZb"],
|
|
186
|
+
["isCR", "a\rZZb", "aZZb"],
|
|
187
|
+
["isLS", "a" + LS + "ZZb", "aZZb"],
|
|
188
|
+
["isPS", "a" + PS + "ZZb", "aZZb"],
|
|
189
|
+
];
|
|
190
|
+
for (const [name, good, bad] of cases) {
|
|
191
|
+
if (mod[name](good) !== true) {
|
|
192
|
+
throw new Error(name + " must accept a value carrying its line terminator: " + JSON.stringify(good));
|
|
193
|
+
}
|
|
194
|
+
if (mod[name](bad) !== false) {
|
|
195
|
+
throw new Error(name + " must reject a value lacking its line terminator: " + JSON.stringify(bad));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (mod.isControl("prefix_mid_postfix") !== true) {
|
|
200
|
+
throw new Error("line-terminator-free template must still accept a conforming value");
|
|
201
|
+
}
|
|
202
|
+
if (mod.isControl("nope") !== false) {
|
|
203
|
+
throw new Error("line-terminator-free template must still reject a non-conforming value");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// A Record index signature only constrains keys its key pattern matches, so the
|
|
207
|
+
// newline in the key regex is what decides which keys get the number check. A
|
|
208
|
+
// matching key with a bad value must fail, while a near-miss key that lacks the
|
|
209
|
+
// newline is not matched (and so is left unchecked) -- together they prove the
|
|
210
|
+
// escaped line terminator is load-bearing in the emitted regex.
|
|
211
|
+
const goodRecord = {};
|
|
212
|
+
goodRecord["a\nkey"] = 1;
|
|
213
|
+
if (mod.isRecord(goodRecord) !== true) {
|
|
214
|
+
throw new Error("Record: a matching key with a number value must pass");
|
|
215
|
+
}
|
|
216
|
+
const matchedBadValue = {};
|
|
217
|
+
matchedBadValue["a\nkey"] = "not a number";
|
|
218
|
+
if (mod.isRecord(matchedBadValue) !== false) {
|
|
219
|
+
throw new Error("Record: a newline-matching key with a non-number value must fail");
|
|
220
|
+
}
|
|
221
|
+
if (mod.isRecord({ "axkey": "not a number" }) !== true) {
|
|
222
|
+
throw new Error("Record: a key lacking the newline must not match the pattern, so it stays unchecked");
|
|
223
|
+
}
|
|
224
|
+
`
|