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,219 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"os/exec"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// TestPlainPruneUnionObjectOvermatchTransform pins prune over mixed unions.
|
|
11
|
+
//
|
|
12
|
+
// PlainPruneProgrammer emits one independent `if` per union member, and the
|
|
13
|
+
// object arm's guard is `IsObject` with `CheckArray:false`, which also matches
|
|
14
|
+
// arrays and native instances. With no `else` the array/native arm AND the
|
|
15
|
+
// object arm both run, so `Object.keys(input)` on a value another arm already
|
|
16
|
+
// owns gets its slots deleted: a typed array throws on `delete input[0]`, a
|
|
17
|
+
// plain array collapses to holes, and a native's own properties are stripped.
|
|
18
|
+
// clone/classify resolve the same unions with a mutually exclusive ladder, so
|
|
19
|
+
// the object arm is only reached when the value is a plain object. This test
|
|
20
|
+
// drives every native kind unioned with an object in both orders, plus an
|
|
21
|
+
// object∪tuple, and requires the native/array/tuple value to survive intact.
|
|
22
|
+
//
|
|
23
|
+
// 1. Transform prune factories over native|object, object|native, array|object
|
|
24
|
+
// and object|tuple unions.
|
|
25
|
+
// 2. Execute prune against a typed array, Date, Map, Set, RegExp, plain array,
|
|
26
|
+
// and tuple, requiring each to keep its identity and own state.
|
|
27
|
+
// 3. Require the object arm still prunes an ordinary object member.
|
|
28
|
+
func TestPlainPruneUnionObjectOvermatchTransform(t *testing.T) {
|
|
29
|
+
project := plainPruneUnionObjectOvermatchProject(t)
|
|
30
|
+
out, errText, code := ttscTypiaTestCapture(func() int {
|
|
31
|
+
return runTransform([]string{
|
|
32
|
+
"--cwd", project,
|
|
33
|
+
"--tsconfig", "tsconfig.json",
|
|
34
|
+
"--file", "src/main.ts",
|
|
35
|
+
"--output", "js",
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
if code != 0 {
|
|
39
|
+
t.Fatalf("prune union/object over-match transform failed: code=%d stderr=\n%s", code, errText)
|
|
40
|
+
}
|
|
41
|
+
plainPruneUnionObjectOvermatchRunRuntimeCases(t, project, out)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func plainPruneUnionObjectOvermatchProject(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, "plain-prune-union-object-")
|
|
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(plainPruneUnionObjectOvermatchTSConfig), 0o644); err != nil {
|
|
63
|
+
t.Fatalf("write tsconfig: %v", err)
|
|
64
|
+
}
|
|
65
|
+
if err := os.WriteFile(filepath.Join(src, "main.ts"), []byte(plainPruneUnionObjectOvermatchSource), 0o644); err != nil {
|
|
66
|
+
t.Fatalf("write source: %v", err)
|
|
67
|
+
}
|
|
68
|
+
return dir
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func plainPruneUnionObjectOvermatchRunRuntimeCases(t *testing.T, project string, js string) {
|
|
72
|
+
t.Helper()
|
|
73
|
+
node, err := exec.LookPath("node")
|
|
74
|
+
if err != nil {
|
|
75
|
+
t.Skip("node executable not found")
|
|
76
|
+
}
|
|
77
|
+
runtimeDir := filepath.Join(project, "runtime")
|
|
78
|
+
if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
|
|
79
|
+
t.Fatalf("mkdir runtime dir: %v", err)
|
|
80
|
+
}
|
|
81
|
+
ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
|
|
82
|
+
runtimeJS := ttscTypiaTestRewriteCommonJS(t, js)
|
|
83
|
+
if err := os.WriteFile(filepath.Join(runtimeDir, "main.cjs"), []byte(runtimeJS), 0o644); err != nil {
|
|
84
|
+
t.Fatalf("write runtime module: %v", err)
|
|
85
|
+
}
|
|
86
|
+
runner := filepath.Join(runtimeDir, "run.cjs")
|
|
87
|
+
if err := os.WriteFile(runner, []byte(plainPruneUnionObjectOvermatchRuntimeRunner), 0o644); err != nil {
|
|
88
|
+
t.Fatalf("write runtime runner: %v", err)
|
|
89
|
+
}
|
|
90
|
+
cmd := exec.Command(node, runner)
|
|
91
|
+
cmd.Dir = runtimeDir
|
|
92
|
+
output, err := cmd.CombinedOutput()
|
|
93
|
+
if err != nil {
|
|
94
|
+
t.Fatalf("prune union/object over-match runtime cases failed: %v\n%s", err, output)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const plainPruneUnionObjectOvermatchTSConfig = `{
|
|
99
|
+
"compilerOptions": {
|
|
100
|
+
"target": "ES2022",
|
|
101
|
+
"module": "commonjs",
|
|
102
|
+
"moduleResolution": "bundler",
|
|
103
|
+
"ignoreDeprecations": "6.0",
|
|
104
|
+
"types": ["*"],
|
|
105
|
+
"esModuleInterop": true,
|
|
106
|
+
"strict": true,
|
|
107
|
+
"skipLibCheck": true
|
|
108
|
+
},
|
|
109
|
+
"include": ["src"]
|
|
110
|
+
}
|
|
111
|
+
`
|
|
112
|
+
|
|
113
|
+
const plainPruneUnionObjectOvermatchSource = `import typia from "typia";
|
|
114
|
+
|
|
115
|
+
interface IBox {
|
|
116
|
+
x: number;
|
|
117
|
+
}
|
|
118
|
+
interface IElem {
|
|
119
|
+
y: number;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export const pruneBytesFirst = typia.plain.createPrune<Uint8Array | IBox>();
|
|
123
|
+
export const pruneBytesLast = typia.plain.createPrune<IBox | Uint8Array>();
|
|
124
|
+
export const pruneDateFirst = typia.plain.createPrune<Date | IBox>();
|
|
125
|
+
export const pruneDateLast = typia.plain.createPrune<IBox | Date>();
|
|
126
|
+
export const pruneMap = typia.plain.createPrune<Map<string, number> | IBox>();
|
|
127
|
+
export const pruneSet = typia.plain.createPrune<IBox | Set<number>>();
|
|
128
|
+
export const pruneRegExp = typia.plain.createPrune<RegExp | IBox>();
|
|
129
|
+
export const pruneArray = typia.plain.createPrune<IElem[] | IBox>();
|
|
130
|
+
export const pruneTuple = typia.plain.createPrune<IBox | [IElem, IElem]>();
|
|
131
|
+
`
|
|
132
|
+
|
|
133
|
+
const plainPruneUnionObjectOvermatchRuntimeRunner = `const mod = require("./main.cjs");
|
|
134
|
+
|
|
135
|
+
const fail = (label, detail) => {
|
|
136
|
+
throw new Error(label + ": " + detail);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// 1. A typed array must survive prune untouched (the buggy object arm throws
|
|
140
|
+
// "Cannot delete property '0'" while deleting its integer-indexed slots).
|
|
141
|
+
for (const [label, prune] of [
|
|
142
|
+
["Uint8Array | IBox", mod.pruneBytesFirst],
|
|
143
|
+
["IBox | Uint8Array", mod.pruneBytesLast],
|
|
144
|
+
]) {
|
|
145
|
+
const bytes = new Uint8Array([1, 2, 3]);
|
|
146
|
+
prune(bytes);
|
|
147
|
+
if (!(bytes instanceof Uint8Array) || bytes.length !== 3 || bytes[0] !== 1 || bytes[1] !== 2 || bytes[2] !== 3)
|
|
148
|
+
fail(label, "typed array corrupted -> " + JSON.stringify(Array.from(bytes)));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// 2. A Date must keep its time and its own state; the object arm strips own keys.
|
|
152
|
+
for (const [label, prune] of [
|
|
153
|
+
["Date | IBox", mod.pruneDateFirst],
|
|
154
|
+
["IBox | Date", mod.pruneDateLast],
|
|
155
|
+
]) {
|
|
156
|
+
const date = new Date(1000);
|
|
157
|
+
date.tag = "keep";
|
|
158
|
+
prune(date);
|
|
159
|
+
if (!(date instanceof Date) || date.getTime() !== 1000)
|
|
160
|
+
fail(label, "Date time corrupted -> " + date.getTime());
|
|
161
|
+
if (date.tag !== "keep")
|
|
162
|
+
fail(label, "Date own property stripped");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 3. A Map / Set must keep their contents and own state.
|
|
166
|
+
{
|
|
167
|
+
const map = new Map([["a", 1]]);
|
|
168
|
+
map.tag = "keep";
|
|
169
|
+
mod.pruneMap(map);
|
|
170
|
+
if (!(map instanceof Map) || map.size !== 1 || map.get("a") !== 1 || map.tag !== "keep")
|
|
171
|
+
fail("Map<string,number> | IBox", "Map corrupted");
|
|
172
|
+
}
|
|
173
|
+
{
|
|
174
|
+
const set = new Set([7]);
|
|
175
|
+
set.tag = "keep";
|
|
176
|
+
mod.pruneSet(set);
|
|
177
|
+
if (!(set instanceof Set) || set.size !== 1 || set.has(7) === false || set.tag !== "keep")
|
|
178
|
+
fail("IBox | Set<number>", "Set corrupted");
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 4. A RegExp with equal source but its own state must survive.
|
|
182
|
+
{
|
|
183
|
+
const re = /abc/gi;
|
|
184
|
+
re.tag = "keep";
|
|
185
|
+
mod.pruneRegExp(re);
|
|
186
|
+
if (!(re instanceof RegExp) || re.source !== "abc" || re.flags !== "gi" || re.tag !== "keep")
|
|
187
|
+
fail("RegExp | IBox", "RegExp corrupted");
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 5. A plain array must be pruned element-by-element, not deleted to holes.
|
|
191
|
+
{
|
|
192
|
+
const arr = [{ y: 1, extra: 2 }, { y: 3, extra: 4 }];
|
|
193
|
+
mod.pruneArray(arr);
|
|
194
|
+
if (!Array.isArray(arr) || arr.length !== 2)
|
|
195
|
+
fail("IElem[] | IBox", "array shape corrupted -> " + JSON.stringify(arr));
|
|
196
|
+
if (arr[0] === undefined || arr[1] === undefined)
|
|
197
|
+
fail("IElem[] | IBox", "array slot deleted -> " + JSON.stringify(arr));
|
|
198
|
+
if (arr[0].y !== 1 || arr[1].y !== 3 || "extra" in arr[0] || "extra" in arr[1])
|
|
199
|
+
fail("IElem[] | IBox", "array elements not pruned as objects -> " + JSON.stringify(arr));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// 6. An object∪tuple must prune the tuple positionally, not delete its slots.
|
|
203
|
+
{
|
|
204
|
+
const tuple = [{ y: 1, extra: 2 }, { y: 3, extra: 4 }];
|
|
205
|
+
mod.pruneTuple(tuple);
|
|
206
|
+
if (!Array.isArray(tuple) || tuple.length !== 2 || tuple[0] === undefined || tuple[1] === undefined)
|
|
207
|
+
fail("IBox | [IElem, IElem]", "tuple slot deleted -> " + JSON.stringify(tuple));
|
|
208
|
+
if (tuple[0].y !== 1 || tuple[1].y !== 3 || "extra" in tuple[0] || "extra" in tuple[1])
|
|
209
|
+
fail("IBox | [IElem, IElem]", "tuple elements not pruned -> " + JSON.stringify(tuple));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// 7. The object arm must still prune an ordinary object member (nothing lost).
|
|
213
|
+
{
|
|
214
|
+
const box = { x: 1, junk: "drop" };
|
|
215
|
+
mod.pruneBytesFirst(box);
|
|
216
|
+
if (box.x !== 1 || "junk" in box)
|
|
217
|
+
fail("Uint8Array | IBox", "object member not pruned -> " + JSON.stringify(box));
|
|
218
|
+
}
|
|
219
|
+
`
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"strings"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// pluginOptionsPayloadCase is one row of the #1887 regression matrix: a project
|
|
11
|
+
// whose tsconfig the user wrote a particular way, the payload ttsc resolves that
|
|
12
|
+
// tsconfig into and hands the plugin, and whether typia's `functional` option is
|
|
13
|
+
// on as a result.
|
|
14
|
+
//
|
|
15
|
+
// `functional` is the probe because its effect is visible in the transform's own
|
|
16
|
+
// output: with the option on, a function-typed property becomes significant and
|
|
17
|
+
// the emitted validator checks it; with the option off, the property is skipped.
|
|
18
|
+
type pluginOptionsPayloadCase struct {
|
|
19
|
+
name string
|
|
20
|
+
// base is a base tsconfig the leaf `extends`, or "" for a single-file project.
|
|
21
|
+
base string
|
|
22
|
+
// leafPlugins is the `compilerOptions.plugins` text of the leaf tsconfig, or
|
|
23
|
+
// "" when the leaf declares no plugins at all.
|
|
24
|
+
leafPlugins string
|
|
25
|
+
// payload is the `--plugins-json` manifest ttsc sends for this project.
|
|
26
|
+
payload string
|
|
27
|
+
// functional is whether the emitted validator must check the function-typed
|
|
28
|
+
// property.
|
|
29
|
+
functional bool
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// pluginOptionsPayloadCases returns the matrix every host must satisfy.
|
|
33
|
+
//
|
|
34
|
+
// Each row pairs the tsconfig the user wrote with the payload the host resolves
|
|
35
|
+
// it into, so the oracle is ttsc's plugin contract rather than typia's current
|
|
36
|
+
// output. The rows are the reproduction table of samchon/typia#1887: the
|
|
37
|
+
// comment and sibling-entry rows prove typia no longer matches option names
|
|
38
|
+
// against raw tsconfig text, and the `extends` row proves it no longer ignores
|
|
39
|
+
// the entry that loaded it.
|
|
40
|
+
func pluginOptionsPayloadCases() []pluginOptionsPayloadCase {
|
|
41
|
+
return []pluginOptionsPayloadCase{
|
|
42
|
+
{
|
|
43
|
+
// The documented shape, and the only one the old scrape read correctly.
|
|
44
|
+
// Pins behavior that must not change.
|
|
45
|
+
name: "option inline on typia's entry",
|
|
46
|
+
leafPlugins: `[{ "transform": "typia/lib/transform", "functional": true }]`,
|
|
47
|
+
payload: `[{"config":{"transform":"typia/lib/transform","functional":true},"name":"typia","stage":"transform"}]`,
|
|
48
|
+
functional: true,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
// The user disabled the option. tsconfig is JSONC, so the host drops the
|
|
52
|
+
// comment and typia's entry carries nothing.
|
|
53
|
+
name: "option commented out with a line comment",
|
|
54
|
+
leafPlugins: `[{
|
|
55
|
+
"transform": "typia/lib/transform"
|
|
56
|
+
// "functional": true
|
|
57
|
+
}]`,
|
|
58
|
+
payload: `[{"config":{"transform":"typia/lib/transform"},"name":"typia","stage":"transform"}]`,
|
|
59
|
+
functional: false,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "option commented out with a block comment",
|
|
63
|
+
leafPlugins: `[{
|
|
64
|
+
"transform": "typia/lib/transform"
|
|
65
|
+
/* "functional": true */
|
|
66
|
+
}]`,
|
|
67
|
+
payload: `[{"config":{"transform":"typia/lib/transform"},"name":"typia","stage":"transform"}]`,
|
|
68
|
+
functional: false,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
// A transform host carries every transform-stage plugin's entry. The
|
|
72
|
+
// option belongs to the sibling, and reading it would be reading someone
|
|
73
|
+
// else's configuration.
|
|
74
|
+
name: "option owned by another plugin's entry",
|
|
75
|
+
leafPlugins: `[
|
|
76
|
+
{ "transform": "other/lib/transform", "functional": true },
|
|
77
|
+
{ "transform": "typia/lib/transform" }
|
|
78
|
+
]`,
|
|
79
|
+
payload: `[
|
|
80
|
+
{"config":{"transform":"other/lib/transform","functional":true},"name":"other","stage":"transform"},
|
|
81
|
+
{"config":{"transform":"typia/lib/transform"},"name":"typia","stage":"transform"}
|
|
82
|
+
]`,
|
|
83
|
+
functional: false,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
// The standard monorepo layout: a shared base declares the plugin and its
|
|
87
|
+
// options, the leaf only extends it. The host resolved the chain and sent
|
|
88
|
+
// the merged entry -- which is why the plugin is running at all.
|
|
89
|
+
name: "option declared in a base tsconfig the leaf extends",
|
|
90
|
+
base: `{
|
|
91
|
+
"compilerOptions": {
|
|
92
|
+
"plugins": [{ "transform": "typia/lib/transform", "functional": true }]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
`,
|
|
96
|
+
payload: `[{"config":{"transform":"typia/lib/transform","functional":true},"name":"typia","stage":"transform"}]`,
|
|
97
|
+
functional: true,
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// pluginOptionsPayloadProject materializes one matrix row as a real project: the
|
|
103
|
+
// tsconfig exactly as the user wrote it (comments, sibling entries, `extends`
|
|
104
|
+
// chain and all), a typia stub to resolve the import against, and a source file
|
|
105
|
+
// with a function-typed property for the option to act on.
|
|
106
|
+
func pluginOptionsPayloadProject(t *testing.T, tc pluginOptionsPayloadCase) string {
|
|
107
|
+
t.Helper()
|
|
108
|
+
project := t.TempDir()
|
|
109
|
+
src := filepath.Join(project, "src")
|
|
110
|
+
if err := os.MkdirAll(src, 0o755); err != nil {
|
|
111
|
+
t.Fatalf("mkdir fixture src: %v", err)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
extends := ""
|
|
115
|
+
if tc.base != "" {
|
|
116
|
+
if err := os.WriteFile(filepath.Join(project, "tsconfig.base.json"), []byte(tc.base), 0o644); err != nil {
|
|
117
|
+
t.Fatalf("write base tsconfig: %v", err)
|
|
118
|
+
}
|
|
119
|
+
extends = `"extends": "./tsconfig.base.json",
|
|
120
|
+
`
|
|
121
|
+
}
|
|
122
|
+
plugins := ""
|
|
123
|
+
if tc.leafPlugins != "" {
|
|
124
|
+
plugins = `,
|
|
125
|
+
"plugins": ` + tc.leafPlugins
|
|
126
|
+
}
|
|
127
|
+
config := `{
|
|
128
|
+
` + extends + `"compilerOptions": {
|
|
129
|
+
"target": "ES2022",
|
|
130
|
+
"module": "commonjs",
|
|
131
|
+
"moduleResolution": "bundler",
|
|
132
|
+
"ignoreDeprecations": "6.0",
|
|
133
|
+
"types": ["*"],
|
|
134
|
+
"esModuleInterop": true,
|
|
135
|
+
"strict": true,
|
|
136
|
+
"skipLibCheck": true,
|
|
137
|
+
"rootDir": "src",
|
|
138
|
+
"outDir": "dist"` + plugins + `
|
|
139
|
+
},
|
|
140
|
+
"include": ["src"]
|
|
141
|
+
}
|
|
142
|
+
`
|
|
143
|
+
if err := os.WriteFile(filepath.Join(project, "tsconfig.json"), []byte(config), 0o644); err != nil {
|
|
144
|
+
t.Fatalf("write tsconfig: %v", err)
|
|
145
|
+
}
|
|
146
|
+
transformDiagnosticWriteTypiaStub(t, project)
|
|
147
|
+
if err := os.WriteFile(filepath.Join(src, "main.ts"), []byte(pluginOptionsPayloadSource), 0o644); err != nil {
|
|
148
|
+
t.Fatalf("write source: %v", err)
|
|
149
|
+
}
|
|
150
|
+
return project
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// pluginOptionsPayloadAssert checks one host's output against the row's expected
|
|
154
|
+
// option state.
|
|
155
|
+
func pluginOptionsPayloadAssert(t *testing.T, tc pluginOptionsPayloadCase, output string) {
|
|
156
|
+
t.Helper()
|
|
157
|
+
checked := pluginOptionsPayloadFunctionalCheck(output)
|
|
158
|
+
if checked == tc.functional {
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
if tc.functional {
|
|
162
|
+
t.Fatalf("functional is configured on but the validator skipped the function property:\n%s", output)
|
|
163
|
+
}
|
|
164
|
+
t.Fatalf("functional is not configured but the validator checked the function property:\n%s", output)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
func pluginOptionsPayloadFunctionalCheck(output string) bool {
|
|
168
|
+
return strings.Contains(output, pluginOptionsPayloadFunctionalNeedle)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// pluginOptionsPayloadFunctionalNeedle is the guard typia emits for the
|
|
172
|
+
// function-typed property only when `functional` is enabled.
|
|
173
|
+
const pluginOptionsPayloadFunctionalNeedle = `"function" === typeof input.cb`
|
|
174
|
+
|
|
175
|
+
const pluginOptionsPayloadSource = `import typia from "typia";
|
|
176
|
+
export interface IX {
|
|
177
|
+
value: number;
|
|
178
|
+
cb: () => void;
|
|
179
|
+
}
|
|
180
|
+
export const check = (input: unknown): boolean => typia.is<IX>(input);
|
|
181
|
+
`
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"os/exec"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"strings"
|
|
8
|
+
"testing"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// TestPrivateFieldFilterIsTransform verifies an ES `#private` instance field is
|
|
12
|
+
// excluded from a class's validated shape, so a real instance passes its own
|
|
13
|
+
// `is`/`assert`/`validate` guard (#2213).
|
|
14
|
+
//
|
|
15
|
+
// A `#private` field is installed only by the constructor and is unreachable via
|
|
16
|
+
// index access, so it is not part of a type's structural, externally-observable
|
|
17
|
+
// shape. Before the fix the member filter excluded only the TypeScript keyword
|
|
18
|
+
// `private`/`protected` members, so a `#private` field leaked into the validated
|
|
19
|
+
// shape as a mangled key (`input["�#1@#secret"]`) that no runtime object
|
|
20
|
+
// carries — making the guard unconditionally false.
|
|
21
|
+
//
|
|
22
|
+
// 1. Emit `is`/`assert`/`validate` for a class carrying a `#private` field
|
|
23
|
+
// alongside a public property, a subclass that adds another `#private`, an
|
|
24
|
+
// all-`#private` class, a class with `#private` method / accessor members,
|
|
25
|
+
// and a keyword `private`/`protected` class.
|
|
26
|
+
// 2. Assert the emitted validators never reference a mangled `#private` key.
|
|
27
|
+
// 3. Execute the validators against real instances and plain public-shape
|
|
28
|
+
// objects, proving each passes on its public shape.
|
|
29
|
+
func TestPrivateFieldFilterIsTransform(t *testing.T) {
|
|
30
|
+
project := privateFieldFilterProject(t)
|
|
31
|
+
|
|
32
|
+
ts := privateFieldFilterTransform(t, project, "ts")
|
|
33
|
+
// A `#private` member surfaces in a validator only as a mangled key —
|
|
34
|
+
// `input["�#1@#secret"]`. The class SOURCE (echoed above the validators)
|
|
35
|
+
// also spells `#secret`, so the bare name is not a defect marker; the `@#`
|
|
36
|
+
// infix is unique to the mangled key and never appears in class source, so it
|
|
37
|
+
// is the exact byte signature of the leak.
|
|
38
|
+
if strings.Contains(ts, "@#") {
|
|
39
|
+
t.Fatalf("emit references a mangled #private key (leaked into validated shape):\n%s", ts)
|
|
40
|
+
}
|
|
41
|
+
// The public shape must still be validated.
|
|
42
|
+
for _, needle := range []string{"input.label", "input.tag"} {
|
|
43
|
+
if !strings.Contains(ts, needle) {
|
|
44
|
+
t.Fatalf("emit dropped a public property %q:\n%s", needle, ts)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
privateFieldFilterRunRuntimeCases(
|
|
49
|
+
t,
|
|
50
|
+
project,
|
|
51
|
+
privateFieldFilterTransform(t, project, "js"),
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func privateFieldFilterProject(t *testing.T) string {
|
|
56
|
+
t.Helper()
|
|
57
|
+
root := ttscTypiaTestRepoRoot(t)
|
|
58
|
+
base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
|
|
59
|
+
if err := os.MkdirAll(base, 0o755); err != nil {
|
|
60
|
+
t.Fatalf("mkdir temp base: %v", err)
|
|
61
|
+
}
|
|
62
|
+
dir, err := os.MkdirTemp(base, "private-field-filter-")
|
|
63
|
+
if err != nil {
|
|
64
|
+
t.Fatalf("create temp fixture: %v", err)
|
|
65
|
+
}
|
|
66
|
+
t.Cleanup(func() {
|
|
67
|
+
_ = os.RemoveAll(dir)
|
|
68
|
+
})
|
|
69
|
+
src := filepath.Join(dir, "src")
|
|
70
|
+
if err := os.MkdirAll(src, 0o755); err != nil {
|
|
71
|
+
t.Fatalf("mkdir fixture src: %v", err)
|
|
72
|
+
}
|
|
73
|
+
if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(privateFieldFilterTSConfig), 0o644); err != nil {
|
|
74
|
+
t.Fatalf("write tsconfig: %v", err)
|
|
75
|
+
}
|
|
76
|
+
if err := os.WriteFile(filepath.Join(src, "main.ts"), []byte(privateFieldFilterSource), 0o644); err != nil {
|
|
77
|
+
t.Fatalf("write source: %v", err)
|
|
78
|
+
}
|
|
79
|
+
return dir
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
func privateFieldFilterTransform(t *testing.T, project string, output string) string {
|
|
83
|
+
t.Helper()
|
|
84
|
+
out, errText, code := ttscTypiaTestCapture(func() int {
|
|
85
|
+
return runTransform([]string{
|
|
86
|
+
"--cwd", project,
|
|
87
|
+
"--tsconfig", "tsconfig.json",
|
|
88
|
+
"--file", "src/main.ts",
|
|
89
|
+
"--output", output,
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
if code != 0 {
|
|
93
|
+
t.Fatalf("private field filter transform failed: output=%s code=%d stderr=\n%s", output, code, errText)
|
|
94
|
+
}
|
|
95
|
+
return out
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func privateFieldFilterRunRuntimeCases(t *testing.T, project string, js string) {
|
|
99
|
+
t.Helper()
|
|
100
|
+
node, err := exec.LookPath("node")
|
|
101
|
+
if err != nil {
|
|
102
|
+
t.Skip("node executable not found")
|
|
103
|
+
}
|
|
104
|
+
runtimeDir := filepath.Join(project, "runtime")
|
|
105
|
+
if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
|
|
106
|
+
t.Fatalf("mkdir runtime dir: %v", err)
|
|
107
|
+
}
|
|
108
|
+
ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
|
|
109
|
+
runtimeJS := ttscTypiaTestRewriteCommonJS(t, js)
|
|
110
|
+
if err := os.WriteFile(filepath.Join(runtimeDir, "main.cjs"), []byte(runtimeJS), 0o644); err != nil {
|
|
111
|
+
t.Fatalf("write runtime module: %v", err)
|
|
112
|
+
}
|
|
113
|
+
runner := filepath.Join(runtimeDir, "run.cjs")
|
|
114
|
+
if err := os.WriteFile(runner, []byte(privateFieldFilterRuntimeRunner), 0o644); err != nil {
|
|
115
|
+
t.Fatalf("write runtime runner: %v", err)
|
|
116
|
+
}
|
|
117
|
+
cmd := exec.Command(node, runner)
|
|
118
|
+
cmd.Dir = runtimeDir
|
|
119
|
+
if output, err := cmd.CombinedOutput(); err != nil {
|
|
120
|
+
t.Fatalf("private field filter runtime cases failed: %v\n%s", err, output)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const privateFieldFilterTSConfig = `{
|
|
125
|
+
"compilerOptions": {
|
|
126
|
+
"target": "ES2022",
|
|
127
|
+
"module": "commonjs",
|
|
128
|
+
"moduleResolution": "bundler",
|
|
129
|
+
"ignoreDeprecations": "6.0",
|
|
130
|
+
"types": ["*"],
|
|
131
|
+
"esModuleInterop": true,
|
|
132
|
+
"strict": true,
|
|
133
|
+
"skipLibCheck": true
|
|
134
|
+
},
|
|
135
|
+
"include": ["src"]
|
|
136
|
+
}
|
|
137
|
+
`
|
|
138
|
+
|
|
139
|
+
const privateFieldFilterSource = `import typia from "typia";
|
|
140
|
+
|
|
141
|
+
export class Box {
|
|
142
|
+
#secret: boolean;
|
|
143
|
+
public label: string;
|
|
144
|
+
constructor(label: string, secret: boolean) {
|
|
145
|
+
this.label = label;
|
|
146
|
+
this.#secret = secret;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export class SubBox extends Box {
|
|
151
|
+
#extra: number;
|
|
152
|
+
public tag: string;
|
|
153
|
+
constructor() {
|
|
154
|
+
super("hi", true);
|
|
155
|
+
this.#extra = 1;
|
|
156
|
+
this.tag = "t";
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export class SoloPrivate {
|
|
161
|
+
#solo: string;
|
|
162
|
+
constructor() {
|
|
163
|
+
this.#solo = "x";
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export class MethodPrivate {
|
|
168
|
+
public label: string;
|
|
169
|
+
#hidden(): number {
|
|
170
|
+
return 1;
|
|
171
|
+
}
|
|
172
|
+
get #view(): number {
|
|
173
|
+
return 2;
|
|
174
|
+
}
|
|
175
|
+
set #view(_next: number) {}
|
|
176
|
+
constructor(label: string) {
|
|
177
|
+
this.label = label;
|
|
178
|
+
void this.#hidden();
|
|
179
|
+
this.#view = this.#view;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export class KeywordBox {
|
|
184
|
+
private secret: boolean;
|
|
185
|
+
protected token: string;
|
|
186
|
+
public label: string;
|
|
187
|
+
constructor(label: string, secret: boolean, token: string) {
|
|
188
|
+
this.label = label;
|
|
189
|
+
this.secret = secret;
|
|
190
|
+
this.token = token;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export const isBox = typia.createIs<Box>();
|
|
195
|
+
export const assertBox = typia.createAssert<Box>();
|
|
196
|
+
export const validateBox = typia.createValidate<Box>();
|
|
197
|
+
export const isSubBox = typia.createIs<SubBox>();
|
|
198
|
+
export const isSolo = typia.createIs<SoloPrivate>();
|
|
199
|
+
export const isMethod = typia.createIs<MethodPrivate>();
|
|
200
|
+
export const isKeyword = typia.createIs<KeywordBox>();
|
|
201
|
+
`
|
|
202
|
+
|
|
203
|
+
const privateFieldFilterRuntimeRunner = `const mod = require("./main.cjs");
|
|
204
|
+
|
|
205
|
+
class Box {
|
|
206
|
+
#secret;
|
|
207
|
+
label;
|
|
208
|
+
constructor(label, secret) {
|
|
209
|
+
this.label = label;
|
|
210
|
+
this.#secret = secret;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
class SubBox extends Box {
|
|
214
|
+
#extra;
|
|
215
|
+
tag;
|
|
216
|
+
constructor() {
|
|
217
|
+
super("hi", true);
|
|
218
|
+
this.#extra = 1;
|
|
219
|
+
this.tag = "t";
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
class SoloPrivate {
|
|
223
|
+
#solo;
|
|
224
|
+
constructor() {
|
|
225
|
+
this.#solo = "x";
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
class MethodPrivate {
|
|
229
|
+
label;
|
|
230
|
+
#hidden() {
|
|
231
|
+
return 1;
|
|
232
|
+
}
|
|
233
|
+
get #view() {
|
|
234
|
+
return 2;
|
|
235
|
+
}
|
|
236
|
+
set #view(_next) {}
|
|
237
|
+
constructor(label) {
|
|
238
|
+
this.label = label;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const expect = (label, actual, expected) => {
|
|
243
|
+
if (actual !== expected) {
|
|
244
|
+
throw new Error(label + ": expected " + expected + " but got " + actual);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// A real instance carrying #private members passes its own guard.
|
|
249
|
+
expect("is real Box instance", mod.isBox(new Box("hi", true)), true);
|
|
250
|
+
expect("is real SubBox instance", mod.isSubBox(new SubBox()), true);
|
|
251
|
+
expect("is real SoloPrivate instance", mod.isSolo(new SoloPrivate()), true);
|
|
252
|
+
expect("is real MethodPrivate instance", mod.isMethod(new MethodPrivate("hi")), true);
|
|
253
|
+
|
|
254
|
+
// The #private field is not part of the structural shape: a plain object with
|
|
255
|
+
// only the public members is accepted, exactly like a keyword-private class.
|
|
256
|
+
expect("is plain public Box shape", mod.isBox({ label: "hi" }), true);
|
|
257
|
+
expect("is plain public SubBox shape", mod.isSubBox({ label: "hi", tag: "t" }), true);
|
|
258
|
+
expect("is empty SoloPrivate shape", mod.isSolo({}), true);
|
|
259
|
+
expect("is plain public MethodPrivate shape", mod.isMethod({ label: "hi" }), true);
|
|
260
|
+
expect("is plain public KeywordBox shape", mod.isKeyword({ label: "hi" }), true);
|
|
261
|
+
|
|
262
|
+
// The public shape is still validated structurally.
|
|
263
|
+
expect("reject wrong public label type", mod.isBox({ label: 123 }), false);
|
|
264
|
+
expect("reject missing public label", mod.isBox({}), false);
|
|
265
|
+
|
|
266
|
+
// assert / validate accept a real instance without touching a mangled key.
|
|
267
|
+
expect("assert real Box returns input", mod.assertBox(new Box("hi", true)) instanceof Box, true);
|
|
268
|
+
expect("validate real Box succeeds", mod.validateBox(new Box("hi", true)).success, true);
|
|
269
|
+
expect("validate plain public Box succeeds", mod.validateBox({ label: "hi" }).success, true);
|
|
270
|
+
|
|
271
|
+
let threw = false;
|
|
272
|
+
try {
|
|
273
|
+
mod.assertBox({ label: 123 });
|
|
274
|
+
} catch (_exp) {
|
|
275
|
+
threw = true;
|
|
276
|
+
}
|
|
277
|
+
expect("assert rejects wrong public label", threw, true);
|
|
278
|
+
`
|