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.
- package/lib/executable/FileSystemIdentity.d.ts +23 -0
- package/lib/executable/FileSystemIdentity.js +30 -0
- package/lib/executable/FileSystemIdentity.js.map +1 -1
- package/lib/executable/FileSystemIdentity.mjs +4 -0
- package/lib/executable/FileSystemIdentity.mjs.map +1 -1
- package/lib/executable/TypiaGenerateWizard.js +15 -9
- package/lib/executable/TypiaGenerateWizard.js.map +1 -1
- package/lib/executable/TypiaGenerateWizard.mjs +11 -7
- package/lib/executable/TypiaGenerateWizard.mjs.map +1 -1
- package/lib/internal/_ProtobufReader.d.ts +18 -3
- package/lib/internal/_ProtobufReader.js +39 -11
- package/lib/internal/_ProtobufReader.js.map +1 -1
- package/lib/internal/_ProtobufReader.mjs +37 -10
- package/lib/internal/_ProtobufReader.mjs.map +1 -1
- package/lib/internal/_jsonStringifyArray.d.ts +1 -0
- package/lib/internal/_jsonStringifyArray.js +48 -0
- package/lib/internal/_jsonStringifyArray.js.map +1 -0
- package/lib/internal/_jsonStringifyArray.mjs +40 -0
- package/lib/internal/_jsonStringifyArray.mjs.map +1 -0
- package/lib/internal/_jsonStringifyElement.d.ts +1 -0
- package/lib/internal/_jsonStringifyElement.js +23 -0
- package/lib/internal/_jsonStringifyElement.js.map +1 -0
- package/lib/internal/_jsonStringifyElement.mjs +23 -0
- package/lib/internal/_jsonStringifyElement.mjs.map +1 -0
- package/lib/internal/_jsonStringifyProperty.d.ts +1 -0
- package/lib/internal/_jsonStringifyProperty.js +31 -0
- package/lib/internal/_jsonStringifyProperty.js.map +1 -0
- package/lib/internal/_jsonStringifyProperty.mjs +31 -0
- package/lib/internal/_jsonStringifyProperty.mjs.map +1 -0
- package/lib/internal/_llmApplicationFinalize.js +1 -1
- package/lib/internal/_llmApplicationFinalize.js.map +1 -1
- package/lib/internal/_llmApplicationFinalize.mjs +1 -1
- package/lib/internal/_llmApplicationFinalize.mjs.map +1 -1
- package/lib/internal/_randomFormatByte.js +24 -1
- package/lib/internal/_randomFormatByte.js.map +1 -1
- package/lib/internal/_randomFormatByte.mjs +20 -2
- package/lib/internal/_randomFormatByte.mjs.map +1 -1
- package/lib/internal/_randomFormatDate.d.ts +3 -6
- package/lib/internal/_randomFormatDate.js +2 -10
- package/lib/internal/_randomFormatDate.js.map +1 -1
- package/lib/internal/_randomFormatDate.mjs +2 -6
- package/lib/internal/_randomFormatDate.mjs.map +1 -1
- package/lib/internal/_randomFormatDatetime.d.ts +3 -6
- package/lib/internal/_randomFormatDatetime.js +25 -8
- package/lib/internal/_randomFormatDatetime.js.map +1 -1
- package/lib/internal/_randomFormatDatetime.mjs +17 -7
- package/lib/internal/_randomFormatDatetime.mjs.map +1 -1
- package/lib/internal/_randomFormatDuration.js +23 -15
- package/lib/internal/_randomFormatDuration.js.map +1 -1
- package/lib/internal/_randomFormatDuration.mjs +23 -15
- package/lib/internal/_randomFormatDuration.mjs.map +1 -1
- package/lib/internal/_randomFormatIpv4.js +31 -1
- package/lib/internal/_randomFormatIpv4.js.map +1 -1
- package/lib/internal/_randomFormatIpv4.mjs +23 -2
- package/lib/internal/_randomFormatIpv4.mjs.map +1 -1
- package/lib/internal/_randomFormatIpv6.js +57 -1
- package/lib/internal/_randomFormatIpv6.js.map +1 -1
- package/lib/internal/_randomFormatIpv6.mjs +45 -2
- package/lib/internal/_randomFormatIpv6.mjs.map +1 -1
- package/lib/internal/_randomFormatJsonPointer.js +14 -2
- package/lib/internal/_randomFormatJsonPointer.js.map +1 -1
- package/lib/internal/_randomFormatJsonPointer.mjs +13 -3
- package/lib/internal/_randomFormatJsonPointer.mjs.map +1 -1
- package/lib/internal/_randomFormatRegex.js +14 -1
- package/lib/internal/_randomFormatRegex.js.map +1 -1
- package/lib/internal/_randomFormatRegex.mjs +14 -2
- package/lib/internal/_randomFormatRegex.mjs.map +1 -1
- package/lib/internal/_randomFormatRelativeJsonPointer.js +19 -5
- package/lib/internal/_randomFormatRelativeJsonPointer.js.map +1 -1
- package/lib/internal/_randomFormatRelativeJsonPointer.mjs +21 -6
- package/lib/internal/_randomFormatRelativeJsonPointer.mjs.map +1 -1
- package/lib/internal/_randomFormatTime.js +33 -7
- package/lib/internal/_randomFormatTime.js.map +1 -1
- package/lib/internal/_randomFormatTime.mjs +37 -5
- package/lib/internal/_randomFormatTime.mjs.map +1 -1
- package/lib/internal/_randomPattern.js.map +1 -1
- package/lib/internal/_randomPattern.mjs.map +1 -1
- package/lib/internal/_randomStringLength.d.ts +41 -10
- package/lib/internal/_randomStringLength.js +49 -13
- package/lib/internal/_randomStringLength.js.map +1 -1
- package/lib/internal/_randomStringLength.mjs +48 -13
- package/lib/internal/_randomStringLength.mjs.map +1 -1
- package/lib/internal/private/__notationRename.js.map +1 -1
- package/lib/internal/private/__notationRename.mjs.map +1 -1
- package/lib/internal/private/__randomComposition.d.ts +23 -0
- package/lib/internal/private/__randomComposition.js +48 -0
- package/lib/internal/private/__randomComposition.js.map +1 -0
- package/lib/internal/private/__randomComposition.mjs +54 -0
- package/lib/internal/private/__randomComposition.mjs.map +1 -0
- package/lib/internal/private/__randomEpoch.d.ts +19 -0
- package/lib/internal/private/__randomEpoch.js +31 -0
- package/lib/internal/private/__randomEpoch.js.map +1 -0
- package/lib/internal/private/__randomEpoch.mjs +28 -0
- package/lib/internal/private/__randomEpoch.mjs.map +1 -0
- package/native/cmd/ttsc-typia/build.go +3 -0
- package/native/cmd/ttsc-typia/callable_interface_function_semantics_transform_test.go +331 -0
- package/native/cmd/ttsc-typia/callable_type_literal_boundaries_transform_test.go +1184 -0
- package/native/cmd/ttsc-typia/compare_functional_union_membership_transform_test.go +434 -0
- package/native/cmd/ttsc-typia/compare_template_literal_union_transform_test.go +241 -0
- package/native/cmd/ttsc-typia/default_library_spoof_native_identity_transform_test.go +216 -0
- package/native/cmd/ttsc-typia/json_schema_dynamic_key_determinism_transform_test.go +246 -0
- package/native/cmd/ttsc-typia/json_stringify_contextual_undefined_transform_test.go +556 -0
- package/native/cmd/ttsc-typia/lib_replacement_native_identity_transform_test.go +277 -0
- package/native/cmd/ttsc-typia/native_named_intersection_union_transform_test.go +390 -0
- package/native/cmd/ttsc-typia/node_buffer_native_exports_is_transform_test.go +526 -0
- package/native/cmd/ttsc-typia/package_declaration_native_identity_is_transform_test.go +293 -0
- package/native/cmd/ttsc-typia/protobuf_diagnostic_code_transform_test.go +167 -0
- package/native/cmd/ttsc-typia/symbol_index_domain_transform_test.go +316 -0
- package/native/cmd/ttsc-typia/transform.go +23 -0
- package/native/cmd/ttsc-typia/transform_helpers_test.go +77 -2
- package/native/cmd/ttsc-typia/user_global_native_identity_transform_test.go +484 -0
- package/native/core/factories/ProtobufFactory.go +6 -1
- package/native/core/factories/internal/metadata/MetadataHelper.go +185 -30
- package/native/core/factories/internal/metadata/emplace_metadata_object.go +25 -0
- package/native/core/factories/internal/metadata/iterate_metadata_function.go +1 -1
- package/native/core/factories/internal/metadata/iterate_metadata_intersection.go +103 -23
- package/native/core/factories/internal/metadata/iterate_metadata_map.go +3 -7
- package/native/core/factories/internal/metadata/iterate_metadata_native.go +32 -14
- package/native/core/factories/internal/metadata/iterate_metadata_set.go +3 -7
- package/native/core/programmers/compare/CompareEqualProgrammer.go +27 -13
- package/native/core/programmers/helpers/FunctionProgrammer.go +6 -13
- package/native/core/programmers/helpers/StringifyJoinder.go +129 -50
- package/native/core/programmers/helpers/joiner_branch_coverage_test.go +116 -120
- package/native/core/programmers/iterate/iterate_check_coverage_test.go +76 -158
- package/native/core/programmers/iterate/iterate_utility_coverage_test.go +231 -270
- package/native/core/programmers/iterate/json_schema_object.go +49 -7
- package/native/core/programmers/iterate/json_schema_pattern_property_order_test.go +44 -0
- package/native/core/programmers/iterate/openapi_v3_downgrader.go +34 -1
- package/native/core/programmers/iterate/template_runtime_pattern.go +11 -0
- package/native/core/programmers/json/JsonStringifyProgrammer.go +47 -6
- package/native/core/programmers/llm/LlmApplicationProgrammer.go +9 -1
- package/native/core/programmers/protobuf/ProtobufMessageProgrammer.go +1 -1
- package/native/core/schemas/metadata/MetadataCollection.go +0 -9
- package/native/core/schemas/metadata/MetadataDefaultLibrary.go +81 -0
- package/native/core/schemas/metadata/MetadataObjectType.go +7 -18
- package/native/go.mod +4 -4
- package/native/transform/features/protobuf/ProtobufMessageTransformer.go +1 -1
- package/package.json +3 -7
- package/src/executable/FileSystemIdentity.ts +33 -0
- package/src/executable/TypiaGenerateWizard.ts +18 -12
- package/src/internal/_ProtobufReader.ts +40 -11
- package/src/internal/_jsonStringifyArray.ts +50 -0
- package/src/internal/_jsonStringifyElement.ts +19 -0
- package/src/internal/_jsonStringifyProperty.ts +30 -0
- package/src/internal/_llmApplicationFinalize.ts +6 -1
- package/src/internal/_randomFormatByte.ts +30 -3
- package/src/internal/_randomFormatDate.ts +4 -20
- package/src/internal/_randomFormatDatetime.ts +34 -20
- package/src/internal/_randomFormatDuration.ts +19 -4
- package/src/internal/_randomFormatIpv4.ts +43 -3
- package/src/internal/_randomFormatIpv6.ts +67 -3
- package/src/internal/_randomFormatJsonPointer.ts +23 -3
- package/src/internal/_randomFormatRegex.ts +21 -3
- package/src/internal/_randomFormatRelativeJsonPointer.ts +23 -10
- package/src/internal/_randomFormatTime.ts +45 -12
- package/src/internal/_randomPattern.ts +4 -1
- package/src/internal/_randomStringLength.ts +61 -17
- package/src/internal/private/__notationRename.ts +1 -4
- package/src/internal/private/__randomComposition.ts +50 -0
- package/src/internal/private/__randomEpoch.ts +34 -0
- package/native/adapter/visit.go +0 -173
- package/native/adapter/visit_property_chain_edges_test.go +0 -129
- package/native/core/programmers/helpers/disable_function_programmer_declare.go +0 -10
- package/native/core/programmers/iterate/check_union_array_like.go +0 -422
- package/native/core/programmers/iterate/prune_object_properties.go +0 -105
- package/native/core/programmers/iterate/stringify_dynamic_properties.go +0 -219
- package/native/core/programmers/iterate/stringify_native.go +0 -14
- package/native/core/programmers/iterate/stringify_regular_properties.go +0 -112
- package/native/core/schemas/metadata/MetadataApplication.go +0 -41
|
@@ -12,6 +12,7 @@ import (
|
|
|
12
12
|
nativefactories "github.com/samchon/typia/packages/typia/native/core/factories"
|
|
13
13
|
nativehelpers "github.com/samchon/typia/packages/typia/native/core/programmers/helpers"
|
|
14
14
|
nativeinternal "github.com/samchon/typia/packages/typia/native/core/programmers/internal"
|
|
15
|
+
nativeiterate "github.com/samchon/typia/packages/typia/native/core/programmers/iterate"
|
|
15
16
|
schemametadata "github.com/samchon/typia/packages/typia/native/core/schemas/metadata"
|
|
16
17
|
)
|
|
17
18
|
|
|
@@ -31,9 +32,10 @@ type CompareEqualProgrammer_IProps struct {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
type compareEqualProgrammerGenerator struct {
|
|
34
|
-
Config
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
Config CompareEqualProgrammer_IConfig
|
|
36
|
+
Functional bool
|
|
37
|
+
Recursive bool
|
|
38
|
+
Counter int
|
|
37
39
|
// Member-resolution checkers (`_ui<index>`) emitted on demand for the object
|
|
38
40
|
// unions that need the is-match ladder, keyed by the object's collection index.
|
|
39
41
|
Matchers []string
|
|
@@ -76,6 +78,7 @@ func (compareEqualProgrammerNamespace) Write(props CompareEqualProgrammer_IProps
|
|
|
76
78
|
|
|
77
79
|
generator := &compareEqualProgrammerGenerator{
|
|
78
80
|
Config: props.Config,
|
|
81
|
+
Functional: nativehelpers.OptionPredicator.Functional(props.Context.Options),
|
|
79
82
|
Recursive: nativeinternal.FeatureProgrammer.CollectionRecursive(collection),
|
|
80
83
|
MatcherIndex: map[int]bool{},
|
|
81
84
|
}
|
|
@@ -307,9 +310,8 @@ func (g *compareEqualProgrammerGenerator) objectCall(object *schemametadata.Meta
|
|
|
307
310
|
return fmt.Sprintf("_eo%d(%s, %s)", object.Index, g.wrap(x), g.wrap(y))
|
|
308
311
|
}
|
|
309
312
|
|
|
310
|
-
// objectFlatBranch renders
|
|
311
|
-
//
|
|
312
|
-
// "union" and as the fallback for a union no supported predicate can split.
|
|
313
|
+
// objectFlatBranch renders a single object member as a guarded comparator. A
|
|
314
|
+
// multi-object union always uses objectUnion's member dispatch instead.
|
|
313
315
|
func (g *compareEqualProgrammerGenerator) objectFlatBranch(object *schemametadata.MetadataObjectType, natives []*schemametadata.MetadataNative, x string, y string) string {
|
|
314
316
|
// Guard the object branch against the sibling native instances. `_eo` admits
|
|
315
317
|
// any `typeof === "object" && !Array.isArray` value, so a native (a Date is
|
|
@@ -439,16 +441,15 @@ func (g *compareEqualProgrammerGenerator) matchCall(object *schemametadata.Metad
|
|
|
439
441
|
// may be absent), and every extra key a dynamic index signature declares must
|
|
440
442
|
// hold a value of the signature's type. It mirrors the `_io` checkers `is`
|
|
441
443
|
// emits, at the abstraction level the rest of this programmer works at — shape
|
|
442
|
-
// and typeof,
|
|
443
|
-
// `
|
|
444
|
+
// and typeof, plus structural template patterns. Function-valued properties
|
|
445
|
+
// participate in this routing check whenever `is` makes them meaningful; they
|
|
446
|
+
// remain excluded from object value comparison after a member is selected. It
|
|
447
|
+
// deliberately ignores `typia.tags.*` constraints.
|
|
444
448
|
func (g *compareEqualProgrammerGenerator) matchObject(object *schemametadata.MetadataObjectType, v string) string {
|
|
445
449
|
checks := []string{}
|
|
446
450
|
regularKeys := []string{}
|
|
447
451
|
dynamic := []*schemametadata.MetadataProperty{}
|
|
448
452
|
for _, property := range object.Properties {
|
|
449
|
-
if compareProgrammer_isMethod(property) {
|
|
450
|
-
continue // methods carry no comparable data, so they do not route either
|
|
451
|
-
}
|
|
452
453
|
if sole := property.Key.GetSoleLiteral(); sole != nil {
|
|
453
454
|
regularKeys = append(regularKeys, *sole)
|
|
454
455
|
checks = append(checks, g.matchSlot(property.Value, g.property(v, *sole)))
|
|
@@ -504,9 +505,9 @@ func (g *compareEqualProgrammerGenerator) match(metadata *schemametadata.Metadat
|
|
|
504
505
|
branches = append(branches, g.typeof(v, atomic.Type))
|
|
505
506
|
}
|
|
506
507
|
if len(metadata.Templates) != 0 {
|
|
507
|
-
branches = append(branches, g.typeof(v, "string"))
|
|
508
|
+
branches = append(branches, g.and(g.typeof(v, "string"), g.template(metadata.Templates, v)))
|
|
508
509
|
}
|
|
509
|
-
if len(metadata.Functions) != 0 {
|
|
510
|
+
if len(metadata.Functions) != 0 && (g.Functional || metadata.Size() != 1) {
|
|
510
511
|
branches = append(branches, g.typeof(v, "function"))
|
|
511
512
|
}
|
|
512
513
|
for _, native := range metadata.Natives {
|
|
@@ -767,6 +768,19 @@ func (g *compareEqualProgrammerGenerator) dynamicKey(metadata *schemametadata.Me
|
|
|
767
768
|
return g.or(checks...)
|
|
768
769
|
}
|
|
769
770
|
|
|
771
|
+
// template renders the structural membership test shared with the authoritative
|
|
772
|
+
// runtime template checker. Compare still ignores typia tag predicates when it
|
|
773
|
+
// compares values, but it must retain the template-literal domain while routing
|
|
774
|
+
// an object union to a declared member.
|
|
775
|
+
func (g *compareEqualProgrammerGenerator) template(templates []*schemametadata.MetadataTemplate, input string) string {
|
|
776
|
+
checks := make([]string, 0, len(templates))
|
|
777
|
+
for _, template := range templates {
|
|
778
|
+
pattern := nativeiterate.TemplateRuntimePattern(template.Row)
|
|
779
|
+
checks = append(checks, fmt.Sprintf("RegExp(%s).test(%s)", strconv.Quote(pattern), g.wrap(input)))
|
|
780
|
+
}
|
|
781
|
+
return g.or(checks...)
|
|
782
|
+
}
|
|
783
|
+
|
|
770
784
|
func (g *compareEqualProgrammerGenerator) visit(kind string, index int) string {
|
|
771
785
|
slot := fmt.Sprintf("_vctx.%s%d", kind, index)
|
|
772
786
|
return fmt.Sprintf("const _map = %s || (%s = new WeakMap()); let _set = _map.get(x); if (_set && _set.has(y)) return true; if (!_set) _map.set(x, (_set = new WeakSet())); _set.add(y);", slot, slot)
|
|
@@ -15,12 +15,11 @@ type FunctionProgrammer struct {
|
|
|
15
15
|
unions_ map[string]*functionProgrammer_union
|
|
16
16
|
unionOrder_ []string
|
|
17
17
|
variables_ map[string]*shimast.Node
|
|
18
|
-
variableKeys_
|
|
18
|
+
variableKeys_ map[string]string
|
|
19
19
|
variableOrder_ []string
|
|
20
|
-
nameIndexes_
|
|
21
|
-
reservedNames_
|
|
20
|
+
nameIndexes_ map[string]int
|
|
21
|
+
reservedNames_ map[string]bool
|
|
22
22
|
sequence_ int
|
|
23
|
-
disableDeclare bool
|
|
24
23
|
// visited_ turns on per-invocation visit tracking: set after metadata
|
|
25
24
|
// analysis when the type graph carries a recursive component, so generated
|
|
26
25
|
// functions thread a `_vctx` context and recursive ones guard against
|
|
@@ -54,10 +53,10 @@ func NewFunctionProgrammer(method string, emit ...*shimprinter.EmitContext) *Fun
|
|
|
54
53
|
unions_: map[string]*functionProgrammer_union{},
|
|
55
54
|
unionOrder_: []string{},
|
|
56
55
|
variables_: map[string]*shimast.Node{},
|
|
57
|
-
variableKeys_:
|
|
56
|
+
variableKeys_: map[string]string{},
|
|
58
57
|
variableOrder_: []string{},
|
|
59
|
-
nameIndexes_:
|
|
60
|
-
reservedNames_:
|
|
58
|
+
nameIndexes_: map[string]int{},
|
|
59
|
+
reservedNames_: map[string]bool{},
|
|
61
60
|
}
|
|
62
61
|
if len(emit) != 0 {
|
|
63
62
|
p.emit_ = emit[0]
|
|
@@ -93,9 +92,6 @@ func (p *FunctionProgrammer) HasLocal(name string) bool {
|
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
func (p *FunctionProgrammer) Declare(includeUnions ...bool) []*shimast.Node {
|
|
96
|
-
if p.disableDeclare {
|
|
97
|
-
return []*shimast.Node{}
|
|
98
|
-
}
|
|
99
95
|
output := []*shimast.Node{}
|
|
100
96
|
for _, name := range p.variableOrder_ {
|
|
101
97
|
value := p.variables_[name]
|
|
@@ -121,9 +117,6 @@ func (p *FunctionProgrammer) Declare(includeUnions ...bool) []*shimast.Node {
|
|
|
121
117
|
}
|
|
122
118
|
|
|
123
119
|
func (p *FunctionProgrammer) DeclareUnions() []*shimast.Node {
|
|
124
|
-
if p.disableDeclare {
|
|
125
|
-
return []*shimast.Node{}
|
|
126
|
-
}
|
|
127
120
|
output := []*shimast.Node{}
|
|
128
121
|
for _, key := range p.unionOrder_ {
|
|
129
122
|
tuple := p.unions_[key]
|
|
@@ -2,7 +2,6 @@ package helpers
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"encoding/json"
|
|
5
|
-
"sort"
|
|
6
5
|
"strings"
|
|
7
6
|
|
|
8
7
|
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
@@ -22,9 +21,10 @@ type StringifyJoiner_ObjectProps struct {
|
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
type StringifyJoiner_ArrayProps struct {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
Context nativecontext.ITypiaContext
|
|
25
|
+
Input *shimast.Expression
|
|
26
|
+
Arrow *shimast.Expression
|
|
27
|
+
Emit *shimprinter.EmitContext
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
type StringifyJoiner_TupleProps struct {
|
|
@@ -49,17 +49,22 @@ func (stringifyJoinerNamespace) Object(props StringifyJoiner_ObjectProps) *shima
|
|
|
49
49
|
dynamic = append(dynamic, entry)
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
expressions := stringifyJoiner_regular_properties(regular, dynamic, props.Context.Emit)
|
|
52
|
+
expressions := stringifyJoiner_regular_properties(props.Context, regular, dynamic, props.Context.Emit)
|
|
53
53
|
if len(dynamic) != 0 {
|
|
54
54
|
keys := make([]string, 0, len(regular))
|
|
55
55
|
for _, entry := range regular {
|
|
56
56
|
keys = append(keys, *entry.Key.GetSoleLiteral())
|
|
57
57
|
}
|
|
58
|
-
expressions = append(expressions, stringifyJoiner_dynamic_properties(dynamic, keys, props.Context.Emit))
|
|
58
|
+
expressions = append(expressions, stringifyJoiner_dynamic_properties(props.Context, dynamic, keys, props.Context.Emit))
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// The tail helper removes the separator left behind when the last written
|
|
62
|
+
// member drops out at runtime, so it may only be skipped when the last regular
|
|
63
|
+
// member cannot drop. Required is not the same as cannot-drop: a required
|
|
64
|
+
// `any` member is omitted whenever its value serializes to `undefined`, which
|
|
65
|
+
// without this produced a trailing comma before `}` (#2253).
|
|
61
66
|
filtered := expressions
|
|
62
|
-
if !((len(regular) != 0 && regular[len(regular)-1]
|
|
67
|
+
if !((len(regular) != 0 && !stringifyJoiner_entry_omittable(regular[len(regular)-1]) && len(dynamic) == 0) ||
|
|
63
68
|
(len(regular) == 0 && len(dynamic) != 0)) {
|
|
64
69
|
filtered = []*shimast.Node{
|
|
65
70
|
f.NewCallExpression(
|
|
@@ -79,27 +84,26 @@ func (stringifyJoinerNamespace) Object(props StringifyJoiner_ObjectProps) *shima
|
|
|
79
84
|
return nativefactories.TemplateFactory.Generate(output, props.Context.Emit)
|
|
80
85
|
}
|
|
81
86
|
|
|
87
|
+
// Array serializes elements through the `_jsonStringifyArray` helper rather than
|
|
88
|
+
// `input.map(...).join(",")`.
|
|
89
|
+
//
|
|
90
|
+
// `map` never visits a hole and leaves one behind, and `join` renders both a
|
|
91
|
+
// hole and a mapped `undefined` as empty text, so the two cases ECMAScript's
|
|
92
|
+
// SerializeJSONArray answers with `null` were emitted as nothing at all: a
|
|
93
|
+
// sparse array produced the malformed text `[,1]`, and an element serializing to
|
|
94
|
+
// `undefined` — a function, a symbol, or a `toJSON` returning nothing in an
|
|
95
|
+
// `any` or `unknown` slot — silently collapsed its position. A hole exists at
|
|
96
|
+
// runtime whatever the element type declares, so this is not confined to `any`
|
|
97
|
+
// (#2253).
|
|
82
98
|
func (stringifyJoinerNamespace) Array(props StringifyJoiner_ArrayProps) *shimast.Node {
|
|
83
99
|
f := nativecontext.EmitFactoryOf(stringifyJoiner_factory, props.Emit)
|
|
84
100
|
return nativefactories.TemplateFactory.Generate([]*shimast.Node{
|
|
85
101
|
f.NewStringLiteral("[", shimast.TokenFlagsNone),
|
|
86
102
|
f.NewCallExpression(
|
|
87
|
-
|
|
88
|
-
nil,
|
|
89
|
-
f.NewCallExpression(
|
|
90
|
-
nativefactories.IdentifierFactory.Access(nil, props.Input, "map"),
|
|
91
|
-
nil,
|
|
92
|
-
nil,
|
|
93
|
-
f.NewNodeList([]*shimast.Node{props.Arrow}),
|
|
94
|
-
shimast.NodeFlagsNone,
|
|
95
|
-
),
|
|
96
|
-
"join",
|
|
97
|
-
),
|
|
103
|
+
stringifyJoiner_internal(props.Context, "jsonStringifyArray"),
|
|
98
104
|
nil,
|
|
99
105
|
nil,
|
|
100
|
-
f.NewNodeList([]*shimast.Node{
|
|
101
|
-
f.NewStringLiteral(",", shimast.TokenFlagsNone),
|
|
102
|
-
}),
|
|
106
|
+
f.NewNodeList([]*shimast.Node{props.Input, props.Arrow}),
|
|
103
107
|
shimast.NodeFlagsNone,
|
|
104
108
|
),
|
|
105
109
|
f.NewStringLiteral("]", shimast.TokenFlagsNone),
|
|
@@ -132,12 +136,17 @@ func (stringifyJoinerNamespace) Tuple(props StringifyJoiner_TupleProps) *shimast
|
|
|
132
136
|
return nativefactories.TemplateFactory.Generate(expressions, props.Emit)
|
|
133
137
|
}
|
|
134
138
|
|
|
135
|
-
func stringifyJoiner_regular_properties(regular []IExpressionEntry, dynamic []IExpressionEntry, emit ...*shimprinter.EmitContext) []*shimast.Node {
|
|
139
|
+
func stringifyJoiner_regular_properties(context nativecontext.ITypiaContext, regular []IExpressionEntry, dynamic []IExpressionEntry, emit ...*shimprinter.EmitContext) []*shimast.Node {
|
|
136
140
|
f := nativecontext.EmitFactoryOf(stringifyJoiner_factory, emit...)
|
|
137
141
|
output := []*shimast.Node{}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
142
|
+
// Members keep their declaration order, which is what the guide promises and
|
|
143
|
+
// what `JSON.stringify` produces for a value assigned in that order. They used
|
|
144
|
+
// to be sorted so every omissible member sat ahead of the required ones,
|
|
145
|
+
// because the separator is appended to every entry but the last and a last
|
|
146
|
+
// member that drops at runtime would leave a trailing comma. The caller
|
|
147
|
+
// already repairs exactly that with `_jsonStringifyTail`, whose condition
|
|
148
|
+
// reads the last member and now sees the declared one, so the ordering
|
|
149
|
+
// constraint the sort existed for no longer applies (#2295).
|
|
141
150
|
for index, entry := range regular {
|
|
142
151
|
key := entry.Key.GetSoleLiteral()
|
|
143
152
|
encoded, err := json.Marshal(*key)
|
|
@@ -149,19 +158,44 @@ func stringifyJoiner_regular_properties(regular []IExpressionEntry, dynamic []IE
|
|
|
149
158
|
// re-escape the JSON bytes for the template-literal context: otherwise `\"`
|
|
150
159
|
// decays to `"`, `\\` to `\`, a control-char escape's backslash is dropped, a
|
|
151
160
|
// raw backtick closes the template, and `${` starts a live interpolation.
|
|
161
|
+
separator := ""
|
|
162
|
+
if index != len(regular)-1 || len(dynamic) != 0 {
|
|
163
|
+
separator = ","
|
|
164
|
+
}
|
|
152
165
|
base := []*shimast.Node{
|
|
153
166
|
f.NewStringLiteral(stringifyJoiner_escape_template(string(encoded))+":", shimast.TokenFlagsNone),
|
|
154
167
|
entry.Expression,
|
|
155
168
|
}
|
|
156
|
-
if
|
|
157
|
-
base = append(base, f.NewStringLiteral(
|
|
169
|
+
if separator != "" {
|
|
170
|
+
base = append(base, f.NewStringLiteral(separator, shimast.TokenFlagsNone))
|
|
158
171
|
}
|
|
159
172
|
empty := (!entry.Meta.IsRequired() && !entry.Meta.Nullable && entry.Meta.Size() == 0) ||
|
|
160
173
|
(len(entry.Meta.Functions) != 0 && !entry.Meta.Nullable && entry.Meta.Size() == 1)
|
|
161
174
|
if empty {
|
|
162
175
|
continue
|
|
163
176
|
}
|
|
164
|
-
if
|
|
177
|
+
if stringifyJoiner_result_undefinable(entry.Meta) {
|
|
178
|
+
// An `any` or `unknown` member is serialized by JSON.stringify, which
|
|
179
|
+
// answers `undefined` for a function, a symbol, and a `toJSON` returning
|
|
180
|
+
// nothing while the value itself is present. Only the serialized result
|
|
181
|
+
// distinguishes those from a value that has text, so the member is written
|
|
182
|
+
// through the helper that reads that result — once, because a `toJSON` may
|
|
183
|
+
// answer differently on a second call (#2253). The input tests below stay
|
|
184
|
+
// for members whose serializer must not run on a missing value at all.
|
|
185
|
+
output = append(output, f.NewCallExpression(
|
|
186
|
+
stringifyJoiner_internal(context, "jsonStringifyProperty"),
|
|
187
|
+
nil,
|
|
188
|
+
nil,
|
|
189
|
+
f.NewNodeList([]*shimast.Node{
|
|
190
|
+
f.NewStringLiteral(string(encoded)+":", shimast.TokenFlagsNone),
|
|
191
|
+
entry.Expression,
|
|
192
|
+
f.NewStringLiteral(separator, shimast.TokenFlagsNone),
|
|
193
|
+
}),
|
|
194
|
+
shimast.NodeFlagsNone,
|
|
195
|
+
))
|
|
196
|
+
continue
|
|
197
|
+
}
|
|
198
|
+
if !entry.Meta.IsRequired() || len(entry.Meta.Functions) != 0 {
|
|
165
199
|
output = append(output, nativefactories.ExpressionFactory.Conditional(
|
|
166
200
|
stringifyJoiner_regular_condition(entry, emit...),
|
|
167
201
|
f.NewStringLiteral("", shimast.TokenFlagsNone),
|
|
@@ -175,6 +209,39 @@ func stringifyJoiner_regular_properties(regular []IExpressionEntry, dynamic []IE
|
|
|
175
209
|
return output
|
|
176
210
|
}
|
|
177
211
|
|
|
212
|
+
// stringifyJoiner_entry_omittable reports whether a member can be absent from
|
|
213
|
+
// the emitted object at runtime, which is exactly the set of members that are
|
|
214
|
+
// written through a conditional or through the property helper.
|
|
215
|
+
func stringifyJoiner_entry_omittable(entry IExpressionEntry) bool {
|
|
216
|
+
return !entry.Meta.IsRequired() || len(entry.Meta.Functions) != 0 ||
|
|
217
|
+
stringifyJoiner_result_undefinable(entry.Meta)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// stringifyJoiner_result_undefinable reports whether a value that is present can
|
|
221
|
+
// still serialize to nothing, which is the case an input test cannot see.
|
|
222
|
+
//
|
|
223
|
+
// `any` and `unknown` are serialized by JSON.stringify, which answers
|
|
224
|
+
// `undefined` for a function, a symbol, and a `toJSON` returning nothing. A
|
|
225
|
+
// declared `toJSON` is the same case without `any`: the member's text is its
|
|
226
|
+
// return value, so a return type that admits `undefined` admits a member with no
|
|
227
|
+
// text (#2253).
|
|
228
|
+
// StringifyJoiner_ResultUndefinable exposes the same question to the element
|
|
229
|
+
// positions the joiner does not build itself, so a tuple slot and an object
|
|
230
|
+
// member classify a value identically.
|
|
231
|
+
func StringifyJoiner_ResultUndefinable(meta *nativemetadata.MetadataSchema) bool {
|
|
232
|
+
return stringifyJoiner_result_undefinable(meta)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
func stringifyJoiner_result_undefinable(meta *nativemetadata.MetadataSchema) bool {
|
|
236
|
+
if meta == nil {
|
|
237
|
+
return false
|
|
238
|
+
}
|
|
239
|
+
if meta.Any {
|
|
240
|
+
return true
|
|
241
|
+
}
|
|
242
|
+
return meta.Escaped != nil && meta.Escaped.Returns != nil && !meta.Escaped.Returns.IsRequired()
|
|
243
|
+
}
|
|
244
|
+
|
|
178
245
|
func stringifyJoiner_regular_condition(entry IExpressionEntry, emit ...*shimprinter.EmitContext) *shimast.Node {
|
|
179
246
|
f := nativecontext.EmitFactoryOf(stringifyJoiner_factory, emit...)
|
|
180
247
|
conditions := []*shimast.Node{}
|
|
@@ -199,7 +266,7 @@ func stringifyJoiner_regular_condition(entry IExpressionEntry, emit ...*shimprin
|
|
|
199
266
|
return stringifyJoiner_reduce(conditions, shimast.KindBarBarToken, emit...)
|
|
200
267
|
}
|
|
201
268
|
|
|
202
|
-
func stringifyJoiner_dynamic_properties(dynamic []IExpressionEntry, regular []string, emit ...*shimprinter.EmitContext) *shimast.Node {
|
|
269
|
+
func stringifyJoiner_dynamic_properties(context nativecontext.ITypiaContext, dynamic []IExpressionEntry, regular []string, emit ...*shimprinter.EmitContext) *shimast.Node {
|
|
203
270
|
f := nativecontext.EmitFactoryOf(stringifyJoiner_factory, emit...)
|
|
204
271
|
statements := []*shimast.Node{
|
|
205
272
|
f.NewIfStatement(
|
|
@@ -298,7 +365,7 @@ func stringifyJoiner_dynamic_properties(dynamic []IExpressionEntry, regular []st
|
|
|
298
365
|
}
|
|
299
366
|
simple := len(dynamic) == 1 && dynamic[0].Key.Size() == 1 && len(dynamic[0].Key.Atomics) != 0 && dynamic[0].Key.Atomics[0].Type == "string"
|
|
300
367
|
if simple {
|
|
301
|
-
statements = append(statements, stringifyJoiner_stringify(dynamic[0], emit...))
|
|
368
|
+
statements = append(statements, stringifyJoiner_stringify(context, dynamic[0], emit...))
|
|
302
369
|
return output()
|
|
303
370
|
}
|
|
304
371
|
for _, entry := range dynamic {
|
|
@@ -313,7 +380,7 @@ func stringifyJoiner_dynamic_properties(dynamic []IExpressionEntry, regular []st
|
|
|
313
380
|
f.NewNodeList([]*shimast.Node{f.NewIdentifier("key")}),
|
|
314
381
|
shimast.NodeFlagsNone,
|
|
315
382
|
),
|
|
316
|
-
stringifyJoiner_stringify(entry, emit...),
|
|
383
|
+
stringifyJoiner_stringify(context, entry, emit...),
|
|
317
384
|
nil,
|
|
318
385
|
))
|
|
319
386
|
}
|
|
@@ -321,20 +388,39 @@ func stringifyJoiner_dynamic_properties(dynamic []IExpressionEntry, regular []st
|
|
|
321
388
|
return output()
|
|
322
389
|
}
|
|
323
390
|
|
|
324
|
-
func stringifyJoiner_stringify(entry IExpressionEntry, emit ...*shimprinter.EmitContext) *shimast.Node {
|
|
391
|
+
func stringifyJoiner_stringify(context nativecontext.ITypiaContext, entry IExpressionEntry, emit ...*shimprinter.EmitContext) *shimast.Node {
|
|
325
392
|
f := nativecontext.EmitFactoryOf(stringifyJoiner_factory, emit...)
|
|
393
|
+
head := nativefactories.TemplateFactory.Generate([]*shimast.Node{
|
|
394
|
+
f.NewCallExpression(
|
|
395
|
+
f.NewIdentifier("JSON.stringify"),
|
|
396
|
+
nil,
|
|
397
|
+
f.NewNodeList(nil),
|
|
398
|
+
f.NewNodeList([]*shimast.Node{f.NewIdentifier("key")}),
|
|
399
|
+
shimast.NodeFlagsNone,
|
|
400
|
+
),
|
|
401
|
+
f.NewStringLiteral(":", shimast.TokenFlagsNone),
|
|
402
|
+
}, emit...)
|
|
403
|
+
if entry.Meta.Any {
|
|
404
|
+
// An index-signature member takes the same contextual decision a static one
|
|
405
|
+
// takes: `any` and `unknown` values are serialized by JSON.stringify, which
|
|
406
|
+
// answers `undefined` for a present function, symbol, or empty `toJSON`.
|
|
407
|
+
// Returning the empty string hands the surrounding filter the same sentinel
|
|
408
|
+
// it already uses for a missing value, so the member and its separator drop
|
|
409
|
+
// together instead of rendering the literal `undefined` (#2253).
|
|
410
|
+
return f.NewReturnStatement(f.NewCallExpression(
|
|
411
|
+
stringifyJoiner_internal(context, "jsonStringifyProperty"),
|
|
412
|
+
nil,
|
|
413
|
+
nil,
|
|
414
|
+
f.NewNodeList([]*shimast.Node{
|
|
415
|
+
head,
|
|
416
|
+
entry.Expression,
|
|
417
|
+
f.NewStringLiteral("", shimast.TokenFlagsNone),
|
|
418
|
+
}),
|
|
419
|
+
shimast.NodeFlagsNone,
|
|
420
|
+
))
|
|
421
|
+
}
|
|
326
422
|
return f.NewReturnStatement(
|
|
327
|
-
nativefactories.TemplateFactory.Generate([]*shimast.Node{
|
|
328
|
-
f.NewCallExpression(
|
|
329
|
-
f.NewIdentifier("JSON.stringify"),
|
|
330
|
-
nil,
|
|
331
|
-
f.NewNodeList(nil),
|
|
332
|
-
f.NewNodeList([]*shimast.Node{f.NewIdentifier("key")}),
|
|
333
|
-
shimast.NodeFlagsNone,
|
|
334
|
-
),
|
|
335
|
-
f.NewStringLiteral(":", shimast.TokenFlagsNone),
|
|
336
|
-
entry.Expression,
|
|
337
|
-
}, emit...),
|
|
423
|
+
nativefactories.TemplateFactory.Generate([]*shimast.Node{head, entry.Expression}, emit...),
|
|
338
424
|
)
|
|
339
425
|
}
|
|
340
426
|
|
|
@@ -380,13 +466,6 @@ func stringifyJoiner_reduce(expressions []*shimast.Node, operator shimast.Kind,
|
|
|
380
466
|
return output
|
|
381
467
|
}
|
|
382
468
|
|
|
383
|
-
func stringifyJoiner_sequence(meta *nativemetadata.MetadataSchema) int {
|
|
384
|
-
if meta.Any || !meta.IsRequired() || len(meta.Functions) != 0 {
|
|
385
|
-
return 0
|
|
386
|
-
}
|
|
387
|
-
return 1
|
|
388
|
-
}
|
|
389
|
-
|
|
390
469
|
func stringifyJoiner_internal(context nativecontext.ITypiaContext, name string) *shimast.Node {
|
|
391
470
|
if importer := context.Importer; importer != nil {
|
|
392
471
|
return importer.Internal(name)
|