typia 13.1.19 → 13.2.0

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.
Files changed (169) hide show
  1. package/lib/executable/FileSystemIdentity.d.ts +23 -0
  2. package/lib/executable/FileSystemIdentity.js +30 -0
  3. package/lib/executable/FileSystemIdentity.js.map +1 -1
  4. package/lib/executable/FileSystemIdentity.mjs +4 -0
  5. package/lib/executable/FileSystemIdentity.mjs.map +1 -1
  6. package/lib/executable/TypiaGenerateWizard.js +15 -9
  7. package/lib/executable/TypiaGenerateWizard.js.map +1 -1
  8. package/lib/executable/TypiaGenerateWizard.mjs +11 -7
  9. package/lib/executable/TypiaGenerateWizard.mjs.map +1 -1
  10. package/lib/internal/_ProtobufReader.d.ts +18 -3
  11. package/lib/internal/_ProtobufReader.js +39 -11
  12. package/lib/internal/_ProtobufReader.js.map +1 -1
  13. package/lib/internal/_ProtobufReader.mjs +37 -10
  14. package/lib/internal/_ProtobufReader.mjs.map +1 -1
  15. package/lib/internal/_jsonStringifyArray.d.ts +1 -0
  16. package/lib/internal/_jsonStringifyArray.js +48 -0
  17. package/lib/internal/_jsonStringifyArray.js.map +1 -0
  18. package/lib/internal/_jsonStringifyArray.mjs +40 -0
  19. package/lib/internal/_jsonStringifyArray.mjs.map +1 -0
  20. package/lib/internal/_jsonStringifyElement.d.ts +1 -0
  21. package/lib/internal/_jsonStringifyElement.js +23 -0
  22. package/lib/internal/_jsonStringifyElement.js.map +1 -0
  23. package/lib/internal/_jsonStringifyElement.mjs +23 -0
  24. package/lib/internal/_jsonStringifyElement.mjs.map +1 -0
  25. package/lib/internal/_jsonStringifyProperty.d.ts +1 -0
  26. package/lib/internal/_jsonStringifyProperty.js +31 -0
  27. package/lib/internal/_jsonStringifyProperty.js.map +1 -0
  28. package/lib/internal/_jsonStringifyProperty.mjs +31 -0
  29. package/lib/internal/_jsonStringifyProperty.mjs.map +1 -0
  30. package/lib/internal/_llmApplicationFinalize.js +1 -1
  31. package/lib/internal/_llmApplicationFinalize.js.map +1 -1
  32. package/lib/internal/_llmApplicationFinalize.mjs +1 -1
  33. package/lib/internal/_llmApplicationFinalize.mjs.map +1 -1
  34. package/lib/internal/_randomFormatByte.js +24 -1
  35. package/lib/internal/_randomFormatByte.js.map +1 -1
  36. package/lib/internal/_randomFormatByte.mjs +20 -2
  37. package/lib/internal/_randomFormatByte.mjs.map +1 -1
  38. package/lib/internal/_randomFormatDate.d.ts +3 -6
  39. package/lib/internal/_randomFormatDate.js +2 -10
  40. package/lib/internal/_randomFormatDate.js.map +1 -1
  41. package/lib/internal/_randomFormatDate.mjs +2 -6
  42. package/lib/internal/_randomFormatDate.mjs.map +1 -1
  43. package/lib/internal/_randomFormatDatetime.d.ts +3 -6
  44. package/lib/internal/_randomFormatDatetime.js +25 -8
  45. package/lib/internal/_randomFormatDatetime.js.map +1 -1
  46. package/lib/internal/_randomFormatDatetime.mjs +17 -7
  47. package/lib/internal/_randomFormatDatetime.mjs.map +1 -1
  48. package/lib/internal/_randomFormatDuration.js +23 -15
  49. package/lib/internal/_randomFormatDuration.js.map +1 -1
  50. package/lib/internal/_randomFormatDuration.mjs +23 -15
  51. package/lib/internal/_randomFormatDuration.mjs.map +1 -1
  52. package/lib/internal/_randomFormatIpv4.js +31 -1
  53. package/lib/internal/_randomFormatIpv4.js.map +1 -1
  54. package/lib/internal/_randomFormatIpv4.mjs +23 -2
  55. package/lib/internal/_randomFormatIpv4.mjs.map +1 -1
  56. package/lib/internal/_randomFormatIpv6.js +57 -1
  57. package/lib/internal/_randomFormatIpv6.js.map +1 -1
  58. package/lib/internal/_randomFormatIpv6.mjs +45 -2
  59. package/lib/internal/_randomFormatIpv6.mjs.map +1 -1
  60. package/lib/internal/_randomFormatJsonPointer.js +14 -2
  61. package/lib/internal/_randomFormatJsonPointer.js.map +1 -1
  62. package/lib/internal/_randomFormatJsonPointer.mjs +13 -3
  63. package/lib/internal/_randomFormatJsonPointer.mjs.map +1 -1
  64. package/lib/internal/_randomFormatRegex.js +14 -1
  65. package/lib/internal/_randomFormatRegex.js.map +1 -1
  66. package/lib/internal/_randomFormatRegex.mjs +14 -2
  67. package/lib/internal/_randomFormatRegex.mjs.map +1 -1
  68. package/lib/internal/_randomFormatRelativeJsonPointer.js +19 -5
  69. package/lib/internal/_randomFormatRelativeJsonPointer.js.map +1 -1
  70. package/lib/internal/_randomFormatRelativeJsonPointer.mjs +21 -6
  71. package/lib/internal/_randomFormatRelativeJsonPointer.mjs.map +1 -1
  72. package/lib/internal/_randomFormatTime.js +33 -7
  73. package/lib/internal/_randomFormatTime.js.map +1 -1
  74. package/lib/internal/_randomFormatTime.mjs +37 -5
  75. package/lib/internal/_randomFormatTime.mjs.map +1 -1
  76. package/lib/internal/_randomPattern.js.map +1 -1
  77. package/lib/internal/_randomPattern.mjs.map +1 -1
  78. package/lib/internal/_randomStringLength.d.ts +41 -10
  79. package/lib/internal/_randomStringLength.js +49 -13
  80. package/lib/internal/_randomStringLength.js.map +1 -1
  81. package/lib/internal/_randomStringLength.mjs +48 -13
  82. package/lib/internal/_randomStringLength.mjs.map +1 -1
  83. package/lib/internal/private/__notationRename.js.map +1 -1
  84. package/lib/internal/private/__notationRename.mjs.map +1 -1
  85. package/lib/internal/private/__randomComposition.d.ts +23 -0
  86. package/lib/internal/private/__randomComposition.js +48 -0
  87. package/lib/internal/private/__randomComposition.js.map +1 -0
  88. package/lib/internal/private/__randomComposition.mjs +54 -0
  89. package/lib/internal/private/__randomComposition.mjs.map +1 -0
  90. package/lib/internal/private/__randomEpoch.d.ts +19 -0
  91. package/lib/internal/private/__randomEpoch.js +31 -0
  92. package/lib/internal/private/__randomEpoch.js.map +1 -0
  93. package/lib/internal/private/__randomEpoch.mjs +28 -0
  94. package/lib/internal/private/__randomEpoch.mjs.map +1 -0
  95. package/native/cmd/ttsc-typia/build.go +3 -0
  96. package/native/cmd/ttsc-typia/callable_interface_function_semantics_transform_test.go +331 -0
  97. package/native/cmd/ttsc-typia/callable_type_literal_boundaries_transform_test.go +1184 -0
  98. package/native/cmd/ttsc-typia/compare_functional_union_membership_transform_test.go +434 -0
  99. package/native/cmd/ttsc-typia/compare_template_literal_union_transform_test.go +241 -0
  100. package/native/cmd/ttsc-typia/default_library_spoof_native_identity_transform_test.go +216 -0
  101. package/native/cmd/ttsc-typia/json_schema_dynamic_key_determinism_transform_test.go +246 -0
  102. package/native/cmd/ttsc-typia/json_stringify_contextual_undefined_transform_test.go +556 -0
  103. package/native/cmd/ttsc-typia/lib_replacement_native_identity_transform_test.go +277 -0
  104. package/native/cmd/ttsc-typia/native_named_intersection_union_transform_test.go +390 -0
  105. package/native/cmd/ttsc-typia/node_buffer_native_exports_is_transform_test.go +526 -0
  106. package/native/cmd/ttsc-typia/package_declaration_native_identity_is_transform_test.go +293 -0
  107. package/native/cmd/ttsc-typia/protobuf_diagnostic_code_transform_test.go +167 -0
  108. package/native/cmd/ttsc-typia/symbol_index_domain_transform_test.go +316 -0
  109. package/native/cmd/ttsc-typia/transform.go +23 -0
  110. package/native/cmd/ttsc-typia/transform_helpers_test.go +77 -2
  111. package/native/cmd/ttsc-typia/user_global_native_identity_transform_test.go +484 -0
  112. package/native/core/factories/ProtobufFactory.go +6 -1
  113. package/native/core/factories/internal/metadata/MetadataHelper.go +185 -30
  114. package/native/core/factories/internal/metadata/emplace_metadata_object.go +25 -0
  115. package/native/core/factories/internal/metadata/iterate_metadata_function.go +1 -1
  116. package/native/core/factories/internal/metadata/iterate_metadata_intersection.go +103 -23
  117. package/native/core/factories/internal/metadata/iterate_metadata_map.go +3 -7
  118. package/native/core/factories/internal/metadata/iterate_metadata_native.go +32 -14
  119. package/native/core/factories/internal/metadata/iterate_metadata_set.go +3 -7
  120. package/native/core/programmers/compare/CompareEqualProgrammer.go +27 -13
  121. package/native/core/programmers/helpers/FunctionProgrammer.go +6 -13
  122. package/native/core/programmers/helpers/StringifyJoinder.go +129 -50
  123. package/native/core/programmers/helpers/joiner_branch_coverage_test.go +116 -120
  124. package/native/core/programmers/iterate/iterate_check_coverage_test.go +76 -158
  125. package/native/core/programmers/iterate/iterate_utility_coverage_test.go +231 -270
  126. package/native/core/programmers/iterate/json_schema_object.go +49 -7
  127. package/native/core/programmers/iterate/json_schema_pattern_property_order_test.go +44 -0
  128. package/native/core/programmers/iterate/openapi_v3_downgrader.go +34 -1
  129. package/native/core/programmers/iterate/template_runtime_pattern.go +11 -0
  130. package/native/core/programmers/json/JsonStringifyProgrammer.go +47 -6
  131. package/native/core/programmers/llm/LlmApplicationProgrammer.go +9 -1
  132. package/native/core/programmers/protobuf/ProtobufMessageProgrammer.go +1 -1
  133. package/native/core/schemas/metadata/MetadataCollection.go +0 -9
  134. package/native/core/schemas/metadata/MetadataDefaultLibrary.go +81 -0
  135. package/native/core/schemas/metadata/MetadataObjectType.go +7 -18
  136. package/native/go.mod +4 -4
  137. package/native/transform/features/protobuf/ProtobufMessageTransformer.go +1 -1
  138. package/package.json +3 -7
  139. package/src/executable/FileSystemIdentity.ts +33 -0
  140. package/src/executable/TypiaGenerateWizard.ts +18 -12
  141. package/src/internal/_ProtobufReader.ts +40 -11
  142. package/src/internal/_jsonStringifyArray.ts +50 -0
  143. package/src/internal/_jsonStringifyElement.ts +19 -0
  144. package/src/internal/_jsonStringifyProperty.ts +30 -0
  145. package/src/internal/_llmApplicationFinalize.ts +6 -1
  146. package/src/internal/_randomFormatByte.ts +30 -3
  147. package/src/internal/_randomFormatDate.ts +4 -20
  148. package/src/internal/_randomFormatDatetime.ts +34 -20
  149. package/src/internal/_randomFormatDuration.ts +19 -4
  150. package/src/internal/_randomFormatIpv4.ts +43 -3
  151. package/src/internal/_randomFormatIpv6.ts +67 -3
  152. package/src/internal/_randomFormatJsonPointer.ts +23 -3
  153. package/src/internal/_randomFormatRegex.ts +21 -3
  154. package/src/internal/_randomFormatRelativeJsonPointer.ts +23 -10
  155. package/src/internal/_randomFormatTime.ts +45 -12
  156. package/src/internal/_randomPattern.ts +4 -1
  157. package/src/internal/_randomStringLength.ts +61 -17
  158. package/src/internal/private/__notationRename.ts +1 -4
  159. package/src/internal/private/__randomComposition.ts +50 -0
  160. package/src/internal/private/__randomEpoch.ts +34 -0
  161. package/native/adapter/visit.go +0 -173
  162. package/native/adapter/visit_property_chain_edges_test.go +0 -129
  163. package/native/core/programmers/helpers/disable_function_programmer_declare.go +0 -10
  164. package/native/core/programmers/iterate/check_union_array_like.go +0 -422
  165. package/native/core/programmers/iterate/prune_object_properties.go +0 -105
  166. package/native/core/programmers/iterate/stringify_dynamic_properties.go +0 -219
  167. package/native/core/programmers/iterate/stringify_native.go +0 -14
  168. package/native/core/programmers/iterate/stringify_regular_properties.go +0 -112
  169. package/native/core/schemas/metadata/MetadataApplication.go +0 -41
@@ -0,0 +1,44 @@
1
+ package iterate
2
+
3
+ import (
4
+ "slices"
5
+ "testing"
6
+
7
+ nativemetadata "github.com/samchon/typia/packages/typia/native/core/schemas/metadata"
8
+ )
9
+
10
+ // TestJsonSchemaPatternPropertyOrderPreservesFirstPosition verifies repeated patterns keep one ordered slot.
11
+ //
12
+ // The legacy TypeScript producer stored pairs in a plain object: assigning an
13
+ // existing pattern replaced its value without moving or duplicating its first
14
+ // insertion position. The Go order record must preserve that overwrite contract.
15
+ //
16
+ // 1. Insert two patterns, then replace the first pattern with new metadata and schema values.
17
+ // 2. Assert the ordered keys remain unique and the map retains the replacement pair.
18
+ func TestJsonSchemaPatternPropertyOrderPreservesFirstPosition(t *testing.T) {
19
+ first := &nativemetadata.MetadataSchema{}
20
+ replacement := &nativemetadata.MetadataSchema{}
21
+ extra := json_schema_superfluous{
22
+ patternProperties: map[string]json_schema_metadata_schema_pair{},
23
+ }
24
+ extra.setPatternProperty("first", json_schema_metadata_schema_pair{
25
+ metadata: first,
26
+ schema: JsonSchema{"type": "string"},
27
+ })
28
+ extra.setPatternProperty("second", json_schema_metadata_schema_pair{
29
+ metadata: &nativemetadata.MetadataSchema{},
30
+ schema: JsonSchema{"type": "boolean"},
31
+ })
32
+ extra.setPatternProperty("first", json_schema_metadata_schema_pair{
33
+ metadata: replacement,
34
+ schema: JsonSchema{"type": "number"},
35
+ })
36
+
37
+ if slices.Equal(extra.patternPropertyKeys, []string{"first", "second"}) == false {
38
+ t.Fatalf("pattern property order was %v", extra.patternPropertyKeys)
39
+ }
40
+ pair := extra.patternProperties["first"]
41
+ if pair.metadata != replacement || pair.schema["type"] != "number" {
42
+ t.Fatalf("replacement pair was not retained: %#v", pair)
43
+ }
44
+ }
@@ -454,7 +454,40 @@ func openApiV3Downgrader_omit_examples(schema JsonSchema) JsonSchema {
454
454
  }
455
455
  output[key] = value
456
456
  }
457
- return output
457
+ return openApiV3Downgrader_exclusive_bounds(output)
458
+ }
459
+
460
+ // openApiV3Downgrader_exclusive_bounds rewrites an exclusive numeric bound into
461
+ // the form the 3.0 dialect defines.
462
+ //
463
+ // 3.0's Schema Object descends from JSON Schema draft-04, where
464
+ // `exclusiveMinimum` and `exclusiveMaximum` are booleans qualifying `minimum`
465
+ // and `maximum`; the numeric spelling belongs to 3.1. Carrying the number
466
+ // through left a document that declares itself 3.0 with a 3.1 keyword, and a
467
+ // 3.0 reader taking the value as the boolean its dialect declares finds no
468
+ // `minimum` beside it and drops the bound entirely (#2300).
469
+ //
470
+ // The upgrader already performs the inverse — a boolean `exclusiveMinimum: true`
471
+ // becomes the numeric bound and the redundant `minimum` is dropped — so this
472
+ // makes the pair a round trip.
473
+ func openApiV3Downgrader_exclusive_bounds(schema JsonSchema) JsonSchema {
474
+ for _, pair := range [][2]string{
475
+ {"exclusiveMinimum", "minimum"},
476
+ {"exclusiveMaximum", "maximum"},
477
+ } {
478
+ value, ok := schema[pair[0]]
479
+ if ok == false {
480
+ continue
481
+ }
482
+ if _, boolean := value.(bool); boolean {
483
+ continue
484
+ }
485
+ if openApiV3Downgrader_is_nil(value) == false {
486
+ schema[pair[1]] = value
487
+ schema[pair[0]] = true
488
+ }
489
+ }
490
+ return schema
458
491
  }
459
492
 
460
493
  // openApiV3Downgrader_shallow_clone copies a schema's own keys, leaving nested
@@ -25,6 +25,17 @@ type templateCapture struct {
25
25
  Atomic *nativemetadata.MetadataAtomic
26
26
  }
27
27
 
28
+ // TemplateRuntimePattern returns the structural regular-expression pattern the
29
+ // runtime template checker uses for one template-literal row.
30
+ //
31
+ // Consumers that only need template membership can share the checker's exact
32
+ // pattern without duplicating its lowering. Runtime tag conditions remain owned
33
+ // by Check_template because they require the checker context and capture map.
34
+ func TemplateRuntimePattern(row []*nativemetadata.MetadataSchema) string {
35
+ pattern, _ := template_runtime_pattern(row)
36
+ return pattern
37
+ }
38
+
28
39
  // template_runtime_pattern builds the structural regex of a template literal for
29
40
  // the runtime checker and, alongside it, the capture map of every constrained
30
41
  // interpolation placeholder.
@@ -278,7 +278,34 @@ func jsonStringifyProgrammer_decode(props struct {
278
278
  Value: func() *shimast.Node {
279
279
  next := props
280
280
  next.Metadata = metadata
281
- return jsonStringifyProgrammer_decode_to_json(next)
281
+ resolved := jsonStringifyProgrammer_decode_to_json(next)
282
+ if isDate {
283
+ return resolved
284
+ }
285
+ // The arm's own test is `typeof input.toJSON === "function"`, but an arm
286
+ // test is not always emitted — a sole arm needs no choice, and a final
287
+ // arm is the else — while this value *calls* `toJSON`. Leaving the call
288
+ // to be guarded by the arm meant a value whose `toJSON` is not callable
289
+ // threw `input.toJSON is not a function` from inside the serializer,
290
+ // including under `isStringify` and `validateStringify`, whose contract
291
+ // is to answer rather than throw (samchon/typia#2271).
292
+ //
293
+ // The guard therefore belongs to the call. `JSON.stringify` ignores a
294
+ // non-callable `toJSON` and serializes the object itself, and the
295
+ // metadata already carries that shape, so the fallback describes the
296
+ // original rather than inventing an answer. `Date` keeps the plain form:
297
+ // its arm is `instanceof Date`, and a real Date's `toJSON` is callable.
298
+ original := props
299
+ original.Metadata = props.Metadata.Escaped.Original
300
+ return nativefactories.ExpressionFactory.Conditional(
301
+ nativeprogrammers.IsProgrammer.Decode_to_json(struct {
302
+ Input *shimast.Expression
303
+ CheckNull bool
304
+ }{Input: props.Input, CheckNull: false}),
305
+ resolved,
306
+ jsonStringifyProgrammer_decode(original),
307
+ props.Context.Emit,
308
+ )
282
309
  },
283
310
  })
284
311
  } else if len(props.Metadata.Functions) != 0 {
@@ -697,9 +724,10 @@ func jsonStringifyProgrammer_decode_array_inline(props jsonStringifyProgrammer_d
697
724
  Arrow *shimast.Node
698
725
  }) *shimast.Node {
699
726
  return nativehelpers.StringifyJoiner.Array(nativehelpers.StringifyJoiner_ArrayProps{
700
- Input: next.Input,
701
- Arrow: next.Arrow,
702
- Emit: props.Context.Emit,
727
+ Context: props.Context,
728
+ Input: next.Input,
729
+ Arrow: next.Arrow,
730
+ Emit: props.Context.Emit,
703
731
  })
704
732
  },
705
733
  Array: props.Array,
@@ -772,7 +800,7 @@ func jsonStringifyProgrammer_decode_tuple_inline(props jsonStringifyProgrammer_d
772
800
  } else {
773
801
  explore.Postfix = fmt.Sprintf("\"[%d]\"", index)
774
802
  }
775
- elements = append(elements, jsonStringifyProgrammer_decode(struct {
803
+ code := jsonStringifyProgrammer_decode(struct {
776
804
  Context nativecontext.ITypiaContext
777
805
  Config nativeinternal.FeatureProgrammer_IConfig
778
806
  Functor *nativehelpers.FunctionProgrammer
@@ -788,7 +816,20 @@ func jsonStringifyProgrammer_decode_tuple_inline(props jsonStringifyProgrammer_d
788
816
  Metadata: elem,
789
817
  Explore: explore,
790
818
  Validated: props.Validated,
791
- }))
819
+ })
820
+ if nativehelpers.StringifyJoiner_ResultUndefinable(elem) {
821
+ // A tuple slot holds its position, so an element that serializes to
822
+ // nothing is `null` rather than omitted; without this its text was the
823
+ // literal `undefined` (#2253).
824
+ code = f.NewCallExpression(
825
+ jsonStringifyProgrammer_internal(props.Context, "jsonStringifyElement"),
826
+ nil,
827
+ nil,
828
+ f.NewNodeList([]*shimast.Node{code}),
829
+ shimast.NodeFlagsNone,
830
+ )
831
+ }
832
+ elements = append(elements, code)
792
833
  }
793
834
  var rest *shimast.Node
794
835
  if len(props.Tuple.Elements) != 0 {
@@ -240,7 +240,15 @@ func (llmApplicationProgrammerNamespace) WriteApplication(props struct {
240
240
  functions = append(functions, written)
241
241
  }
242
242
  }
243
- result := map[string]any{"functions": functions}
243
+ // The call site's schema configuration is resolved here and nowhere else, so
244
+ // it travels with the emitted application; the runtime finalizer only adds
245
+ // the validate hook to it. Rebuilding it at runtime reported `strict: false`
246
+ // for a strict build (issue #2293).
247
+ strict, _ := props.Config["strict"].(bool)
248
+ result := map[string]any{
249
+ "config": map[string]any{"strict": strict},
250
+ "functions": functions,
251
+ }
244
252
  if len(metadata.Objects) != 0 {
245
253
  if object := metadata.Objects[0].Type; object != nil {
246
254
  if description := llmApplicationProgrammer_describe(object.Description, object.JsDocTags); description != nil && len(*description) != 0 {
@@ -35,7 +35,7 @@ func (protobufMessageProgrammerNamespace) Write(props ProtobufMessageProgrammer_
35
35
  f := nativecontext.EmitFactoryOf(protobufMessageProgrammer_factory, props.Context.Emit)
36
36
  collection := schemametadata.NewMetadataCollection()
37
37
  nativefactories.ProtobufFactory.Metadata(nativefactories.ProtobufFactory_IProps{
38
- Method: "message",
38
+ Method: "typia.protobuf.message",
39
39
  Checker: props.Context.Checker,
40
40
  Components: collection,
41
41
  Type: props.Type,
@@ -784,15 +784,6 @@ func metadataCollection_isOpenApiNameRune(ch rune) bool {
784
784
  ch == '_'
785
785
  }
786
786
 
787
- func MetadataCollection_escape(str string) string {
788
- for _, pair := range metadataCollection_replacers {
789
- if pair.After != "" {
790
- str = strings.ReplaceAll(str, pair.After, pair.Before)
791
- }
792
- }
793
- return str
794
- }
795
-
796
787
  type metadataCollection_replacer struct {
797
788
  Before string
798
789
  After string
@@ -0,0 +1,81 @@
1
+ package metadata
2
+
3
+ import (
4
+ "strings"
5
+ "sync"
6
+
7
+ nativeast "github.com/microsoft/typescript-go/shim/ast"
8
+ nativechecker "github.com/microsoft/typescript-go/shim/checker"
9
+ )
10
+
11
+ // MetadataDefaultLibrary routes the compiler's own default-library
12
+ // classification to metadata analysis, which decides runtime-native identity
13
+ // from it: a global is the JavaScript built-in only when a runtime authority —
14
+ // a TypeScript default library, or Node's `buffer` core module — declares it
15
+ // (#2200).
16
+ //
17
+ // Only the program knows which files those are. `bundled:///libs/lib.es2022.d.ts`
18
+ // under the embedded default, an on-disk path under `noembed`, and
19
+ // `node_modules/@typescript/lib-es2022/index.d.ts` under `libReplacement` are
20
+ // all the same authority, and none of them is recognizable from the file name:
21
+ // the last one does not even start with `lib.`, while `lib.d.ts` is an ordinary
22
+ // published file name that any dependency or `typeRoots` package may use
23
+ // (samchon/typia#2108 recorded the same lesson for dependency reporting).
24
+ //
25
+ // The registry is keyed by checker for the same reason MetadataDependency is:
26
+ // analysis code deep inside the metadata iterators holds the checker but no
27
+ // transform context, while one transform host drives one program at a time. A
28
+ // sync.Map keeps unrelated programs in the same process (tests) isolated.
29
+ //
30
+ // When no classifier is registered the file name is the only evidence left, so
31
+ // the fallback is the historical `lib.*.d.ts` base-name test. That keeps a host
32
+ // that never registers on exactly the behavior this package had before the
33
+ // registry existed rather than silently classifying every real native as a
34
+ // user declaration.
35
+ var metadataDefaultLibrary_classifiers sync.Map
36
+
37
+ // MetadataDefaultLibrary_register records the program-level classifier for
38
+ // `checker`. Register it once per loaded program, before any transform runs.
39
+ func MetadataDefaultLibrary_register(checker *nativechecker.Checker, classifier func(*nativeast.SourceFile) bool) {
40
+ if checker == nil || classifier == nil {
41
+ return
42
+ }
43
+ metadataDefaultLibrary_classifiers.Store(checker, classifier)
44
+ }
45
+
46
+ // MetadataDefaultLibrary_release removes the classifier registered for
47
+ // `checker`.
48
+ func MetadataDefaultLibrary_release(checker *nativechecker.Checker) {
49
+ if checker == nil {
50
+ return
51
+ }
52
+ metadataDefaultLibrary_classifiers.Delete(checker)
53
+ }
54
+
55
+ // MetadataDefaultLibrary_is reports whether `source` is one of the program's
56
+ // default library files.
57
+ func MetadataDefaultLibrary_is(checker *nativechecker.Checker, source *nativeast.SourceFile) bool {
58
+ if source == nil {
59
+ return false
60
+ }
61
+ if checker != nil {
62
+ if stored, ok := metadataDefaultLibrary_classifiers.Load(checker); ok {
63
+ if classifier, ok := stored.(func(*nativeast.SourceFile) bool); ok {
64
+ return classifier(source)
65
+ }
66
+ }
67
+ }
68
+ return MetadataDefaultLibrary_isFileNamed(source.FileName())
69
+ }
70
+
71
+ // MetadataDefaultLibrary_isFileNamed is the registry's file-name fallback,
72
+ // exported so the one predicate that still answers without a checker keeps
73
+ // using the same rule.
74
+ func MetadataDefaultLibrary_isFileNamed(fileName string) bool {
75
+ slash := strings.ReplaceAll(fileName, "\\", "/")
76
+ base := slash
77
+ if index := strings.LastIndex(slash, "/"); index >= 0 {
78
+ base = slash[index+1:]
79
+ }
80
+ return strings.HasPrefix(base, "lib.") && strings.HasSuffix(base, ".d.ts")
81
+ }
@@ -13,25 +13,25 @@ type IMetadataSchema_IObjectType struct {
13
13
  }
14
14
 
15
15
  type MetadataObjectType struct {
16
- Name string
17
- DisplayName string
16
+ Name string
17
+ DisplayName string
18
18
  // Source is the absolute-or-as-declared path of the file declaring a named
19
19
  // class, captured at analysis time so plain.classify can value-import a
20
20
  // cross-module class it reconstructs (Object.create / new / from). nil for
21
21
  // anonymous/literal shapes and types with no locatable declaration. Read
22
22
  // in-process by the classify programmer; not serialized (classify is
23
23
  // single-pass), and ignored by clone/prune.
24
- Source *string
24
+ Source *string
25
25
  // SourceDefault is true when the class is the default export of Source, so a
26
26
  // cross-module classify value-import uses a default (not named) import.
27
- SourceDefault bool
27
+ SourceDefault bool
28
28
  // PrivateFields is true when the named class declaration carries at least one
29
29
  // ES `#private` member (a member named with a PrivateIdentifier). Such slots
30
30
  // are installed only by running the constructor; plain.classify's field-copy
31
31
  // (Object.create + assign) cannot restore them, so classify rejects any such
32
32
  // class at a field-copied position. Read in-process by the classify
33
33
  // programmer; ignored by clone/prune, not serialized.
34
- PrivateFields bool
34
+ PrivateFields bool
35
35
  // IsClass is true when this object's declaration is a `class` (declaration or
36
36
  // expression), so it has a runtime VALUE binding plain.classify can
37
37
  // `Object.create(<name>.prototype)`/`new` against. False for an interface, a
@@ -39,7 +39,7 @@ type MetadataObjectType struct {
39
39
  // value, so classify field-copies a plain {} instead of referencing a
40
40
  // type-only name. Read in-process by the classify programmer; ignored by
41
41
  // clone/prune, not serialized.
42
- IsClass bool
42
+ IsClass bool
43
43
  // ValueRef overrides the runtime VALUE-binding name plain.classify uses when
44
44
  // the class's metadata Name is not a usable runtime constructor reference —
45
45
  // namely a NAMED class EXPRESSION (`const X = class Beast {...}`), whose Name
@@ -56,7 +56,7 @@ type MetadataObjectType struct {
56
56
  Validated bool
57
57
  Recursive bool
58
58
  Nullables []bool
59
- Parent_objects_ []*MetadataObject
59
+ Parent_objects_ []*MetadataObject
60
60
  Check_properties_ []*MetadataProperty
61
61
  Tagged_ bool
62
62
  literal_ *bool
@@ -205,17 +205,6 @@ func (obj *MetadataObjectType) ToJSON() IMetadataSchema_IObjectType {
205
205
  }
206
206
  }
207
207
 
208
- func MetadataObjectType_intersects(x *MetadataObjectType, y *MetadataObjectType) bool {
209
- for _, prop := range x.Properties {
210
- for _, oppo := range y.Properties {
211
- if prop.Key.GetName() == oppo.Key.GetName() {
212
- return true
213
- }
214
- }
215
- }
216
- return false
217
- }
218
-
219
208
  func MetadataObjectType_covers(x *MetadataObjectType, y *MetadataObjectType) bool {
220
209
  if len(x.Properties) < len(y.Properties) {
221
210
  return false
package/native/go.mod CHANGED
@@ -5,10 +5,10 @@ go 1.26
5
5
  // Build-time floor: the driver reference-graph SDK
6
6
  // (driver.NewTransformGraph / driver.TransformGraph / driver.TransformOutputKey)
7
7
  // this plugin consumes exists only in ttsc >= 0.19.2. That floor is enforced
8
- // through typia's package.json peerDependencies (ttsc / @ttsc/unplugin), not
9
- // here: ttsc builds this plugin from source on the user's machine and its
10
- // buildSourcePlugin generates `replace github.com/samchon/ttsc/packages/ttsc
11
- // v0.0.0 => <installed ttsc root>`, so the require below must stay v0.0.0 or the
8
+ // through typia's package.json `ttsc` peerDependency, not here: ttsc builds
9
+ // this plugin from source on the user's machine and its buildSourcePlugin
10
+ // generates `replace github.com/samchon/ttsc/packages/ttsc v0.0.0 =>
11
+ // <installed ttsc root>`, so the require below must stay v0.0.0 or the
12
12
  // generated replace no longer matches and the plugin build fails to resolve.
13
13
  require (
14
14
  github.com/microsoft/typescript-go/shim/ast v0.0.0
@@ -20,7 +20,7 @@ func (protobufMessageTransformerNamespace) Transform(props nativetransform.ITran
20
20
  typ := props.Context.Checker.GetTypeFromTypeNode(props.Expression.TypeArguments.Nodes[0])
21
21
  if typ != nil && typ.IsTypeParameter() {
22
22
  panic(nativetransform.NewTransformerError(nativetransform.TransformerError_IProps{
23
- Code: "tyipa.protobuf.message",
23
+ Code: "typia.protobuf.message",
24
24
  Message: "non-specified generic argument.",
25
25
  }))
26
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typia",
3
- "version": "13.1.19",
3
+ "version": "13.2.0",
4
4
  "description": "Superfast runtime validators with only one line",
5
5
  "main": "lib/index.js",
6
6
  "exports": {
@@ -50,17 +50,13 @@
50
50
  "inquirer": "^8.2.5",
51
51
  "randexp": "^0.5.3",
52
52
  "tinyglobby": "^0.2.12",
53
- "@typia/interface": "^13.1.19",
54
- "@typia/utils": "^13.1.19"
53
+ "@typia/interface": "^13.2.0",
54
+ "@typia/utils": "^13.2.0"
55
55
  },
56
56
  "peerDependencies": {
57
- "@ttsc/unplugin": ">=0.19.2",
58
57
  "ttsc": ">=0.19.2"
59
58
  },
60
59
  "peerDependenciesMeta": {
61
- "@ttsc/unplugin": {
62
- "optional": true
63
- },
64
60
  "ttsc": {
65
61
  "optional": true
66
62
  }
@@ -147,6 +147,39 @@ export namespace FileSystemIdentity {
147
147
  );
148
148
  }
149
149
 
150
+ /**
151
+ * Builds the key that decides whether two paths are the same filesystem
152
+ * object.
153
+ *
154
+ * The identity is read from `fs.BigIntStats` rather than `fs.Stats`, because
155
+ * `fs.Stats.ino` is a JavaScript number. An NTFS file ID is `(sequenceNumber
156
+ * << 48) | mftRecordIndex` and routinely exceeds `Number.MAX_SAFE_INTEGER` —
157
+ * in a 4000-directory probe, 1879 of them did — where the spacing between
158
+ * representable doubles is 8 or more. Two entries sharing a sequence number
159
+ * with MFT record indices within that spacing round to one double. The
160
+ * traversal callers would then treat a distinct directory or file as already
161
+ * visited and skip it with no diagnostic, and the overwrite guard would
162
+ * refuse a legitimate output (samchon/typia#2269).
163
+ *
164
+ * A filesystem that reports no inode at all keeps the canonical path
165
+ * fallback, which is the only identity available there.
166
+ *
167
+ * @param stat Stats read with `{ bigint: true }`.
168
+ * @param realpath Canonical path of the same object.
169
+ * @returns Key that is equal for two paths only when they are one object.
170
+ */
171
+ export function identityKey(
172
+ stat: Pick<fs.BigIntStats, "dev" | "ino">,
173
+ realpath: string,
174
+ ): string {
175
+ // `BigInt(0)` rather than `0n`: this package compiles at ES2016, where a
176
+ // BigInt literal is a syntax error, while the constructor and the `bigint`
177
+ // type are fine.
178
+ return stat.ino === BigInt(0)
179
+ ? `path:${path.normalize(realpath)}`
180
+ : `inode:${stat.dev}:${stat.ino}`;
181
+ }
182
+
150
183
  function alternateCase(name: string): string | undefined {
151
184
  let changed: boolean = false;
152
185
  let output: string = "";
@@ -453,7 +453,7 @@ export namespace TypiaGenerateWizard {
453
453
  for (const entry of entries) {
454
454
  inputs.add(
455
455
  fileIdentityKey(
456
- await fs.promises.stat(entry.file),
456
+ await fs.promises.stat(entry.file, { bigint: true }),
457
457
  await fs.promises.realpath(entry.file),
458
458
  ),
459
459
  );
@@ -461,9 +461,9 @@ export namespace TypiaGenerateWizard {
461
461
  }
462
462
 
463
463
  for (const entry of files.values()) {
464
- let stat: fs.Stats;
464
+ let stat: fs.BigIntStats;
465
465
  try {
466
- stat = await fs.promises.lstat(entry.target);
466
+ stat = await fs.promises.lstat(entry.target, { bigint: true });
467
467
  } catch (exp) {
468
468
  if (isMissingFileError(exp)) {
469
469
  continue;
@@ -486,7 +486,7 @@ export namespace TypiaGenerateWizard {
486
486
  `Error on TypiaGenerateWizard.generate(): output file would overwrite input file through a physical file alias: ${entry.target}`,
487
487
  );
488
488
  }
489
- if (stat.nlink > 1) {
489
+ if (stat.nlink > BigInt(1)) {
490
490
  throw new URIError(
491
491
  `Error on TypiaGenerateWizard.generate(): output file has multiple hard links: ${entry.target}`,
492
492
  );
@@ -874,7 +874,9 @@ export namespace TypiaGenerateWizard {
874
874
  real: currentReal,
875
875
  });
876
876
 
877
- const currentStat: fs.Stats = await fs.promises.stat(props.from);
877
+ const currentStat: fs.BigIntStats = await fs.promises.stat(props.from, {
878
+ bigint: true,
879
+ });
878
880
  const directoryIdentity: string = fileIdentityKey(currentStat, currentReal);
879
881
  if (props.visitedDirectories.has(directoryIdentity)) {
880
882
  const lexicalStat: fs.Stats = await fs.promises.lstat(props.from);
@@ -907,14 +909,16 @@ export namespace TypiaGenerateWizard {
907
909
  entries.sort((x, y) => {
908
910
  const linkOrder: number =
909
911
  Number(x.stat.isSymbolicLink()) - Number(y.stat.isSymbolicLink());
910
- return linkOrder !== 0 ? linkOrder : x.name.localeCompare(y.name);
912
+ return linkOrder !== 0
913
+ ? linkOrder
914
+ : Buffer.compare(Buffer.from(x.name), Buffer.from(y.name));
911
915
  });
912
916
 
913
917
  for (const entry of entries) {
914
- let stat: fs.Stats;
918
+ let stat: fs.BigIntStats;
915
919
  let real: string;
916
920
  try {
917
- stat = await fs.promises.stat(entry.file);
921
+ stat = await fs.promises.stat(entry.file, { bigint: true });
918
922
  real = await fs.promises.realpath(entry.file);
919
923
  } catch (error) {
920
924
  throw new URIError(
@@ -1086,10 +1090,12 @@ export namespace TypiaGenerateWizard {
1086
1090
  );
1087
1091
  }
1088
1092
 
1089
- function fileIdentityKey(stat: fs.Stats, realpath: string): string {
1090
- return stat.ino === 0
1091
- ? `path:${path.normalize(realpath)}`
1092
- : `inode:${stat.dev}:${stat.ino}`;
1093
+ /**
1094
+ * Delegates to {@link FileSystemIdentity.identityKey}, which owns the rule and
1095
+ * carries the reasoning for reading the identity as a `bigint`.
1096
+ */
1097
+ function fileIdentityKey(stat: fs.BigIntStats, realpath: string): string {
1098
+ return FileSystemIdentity.identityKey(stat, realpath);
1093
1099
  }
1094
1100
 
1095
1101
  function formatDiagnostics(diagnostics: ITtscCompilerDiagnostic[]): string {
@@ -110,15 +110,19 @@ export class _ProtobufReader {
110
110
  * Advance by exactly one varint, which carries no length prefix.
111
111
  *
112
112
  * A varint terminates at its first byte without the continuation bit, and may
113
- * occupy no more than {@link VARINT_MAX_BYTES}. Reading past that limit would
114
- * accept a varint that `varint32` and `varint64` could not, making the limit
115
- * depend on which method happens to consume the value.
113
+ * occupy no more than {@link VARINT_MAX_BYTES}. Its tenth byte is bounded
114
+ * twice over, by {@link lastVarintByte}: it may neither continue into an
115
+ * eleventh byte nor carry payload above bit 63. Skipping is where that is
116
+ * easiest to get wrong, because this path discards the bytes it reads and so
117
+ * never notices a value it could not have represented. Relaxing either bound
118
+ * here would accept a varint that `varint32` and `varint64` reject, making
119
+ * the limit depend on which method happens to consume the value.
116
120
  */
117
121
  public skipVarint(): void {
118
122
  this.atomic(() => {
119
- for (let i: number = 0; i < VARINT_MAX_BYTES; ++i)
123
+ for (let i: number = 1; i < VARINT_MAX_BYTES; ++i)
120
124
  if ((this.u8() & 0x80) === 0) return;
121
- throw error(`varint exceeds ${VARINT_MAX_BYTES} bytes.`);
125
+ this.lastVarintByte();
122
126
  });
123
127
  }
124
128
 
@@ -172,8 +176,7 @@ export class _ProtobufReader {
172
176
  if (this.u8() < 0x80) return value;
173
177
  if (this.u8() < 0x80) return value;
174
178
  if (this.u8() < 0x80) return value;
175
- if (this.u8() < 0x80) return value;
176
-
179
+ this.lastVarintByte();
177
180
  return value;
178
181
  }
179
182
 
@@ -208,10 +211,28 @@ export class _ProtobufReader {
208
211
  value |= ((loaded = this.u8n()) & BigInt(0x7f)) << BigInt(56);
209
212
  if (loaded < BigInt(0x80)) return value;
210
213
 
211
- value |= (this.u8n() & BigInt(0x01)) << BigInt(63);
214
+ value |= BigInt(this.lastVarintByte()) << BigInt(63);
212
215
  return BigInt.asUintN(64, value);
213
216
  }
214
217
 
218
+ /**
219
+ * Read the only byte whose varint payload is limited to bit 63.
220
+ *
221
+ * Two distinct faults meet on this byte, and each is named for what it is. A
222
+ * continuation bit means the varint would occupy an eleventh byte, which no
223
+ * 64-bit value can reach. Any other payload bit means the varint terminates
224
+ * within its ten bytes but carries a value bit above 63. Reporting the second
225
+ * as a length fault would tell the caller something untrue about a payload
226
+ * that is exactly ten bytes long.
227
+ */
228
+ private lastVarintByte(): number {
229
+ const loaded: number = this.u8();
230
+ if ((loaded & 0x80) !== 0)
231
+ throw error(`varint exceeds ${VARINT_MAX_BYTES} bytes.`);
232
+ if (loaded > 0x01) throw error(`varint exceeds ${VARINT_MAX_BITS} bits.`);
233
+ return loaded;
234
+ }
235
+
215
236
  private u8(): number {
216
237
  return this.view.getUint8(this.take(1));
217
238
  }
@@ -262,12 +283,20 @@ const error = (message: string): Error =>
262
283
  /**
263
284
  * The most bytes a varint may occupy: a 64-bit value in seven-bit groups.
264
285
  *
265
- * `varint32` and `varint64` hold this same limit structurally, by reading no
266
- * further than their tenth byte. This constant is what a loop-driven consumer
267
- * holds it by.
286
+ * Every path reads no further than its tenth byte and accepts only bit 63 from
287
+ * that byte. This constant keeps the loop-driven skip path on the same limit.
268
288
  */
269
289
  const VARINT_MAX_BYTES = 10;
270
290
 
291
+ /**
292
+ * The widest value a varint may carry: the 64-bit Protocol Buffer wire domain.
293
+ *
294
+ * The tenth byte reaches only bit 63, so a payload bit above it belongs to no
295
+ * representable value. This names the overflow fault apart from the length
296
+ * one.
297
+ */
298
+ const VARINT_MAX_BITS = 64;
299
+
271
300
  const utf8 = new Singleton(
272
301
  () => new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }),
273
302
  );