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
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"os/exec"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// TestSymbolIndexDomainTransform verifies a symbol index signature stays out
|
|
11
|
+
// of typia's string-keyed validation and JSON Schema shape (#2240).
|
|
12
|
+
//
|
|
13
|
+
// TypeScript keeps string and symbol index domains distinct, including when a
|
|
14
|
+
// symbol index key is intersected with a nominal brand. This regression pins
|
|
15
|
+
// that boundary through the real transform because treating every checker
|
|
16
|
+
// IndexInfo as a JSON string index makes unrelated Object.keys values inherit a
|
|
17
|
+
// symbol index's value constraint. An ordinary string index and the explicit
|
|
18
|
+
// symbol-member behavior fixed by #2226 are adjacent controls.
|
|
19
|
+
//
|
|
20
|
+
// 1. Compile checker-level keyof assertions for symbol and string indexes.
|
|
21
|
+
// 2. Execute validators over ordinary extras and symbol-valued properties.
|
|
22
|
+
// 3. Compare the symbol-index schema exactly with a plain-object control while
|
|
23
|
+
// requiring a normal string index to retain additionalProperties.
|
|
24
|
+
func TestSymbolIndexDomainTransform(t *testing.T) {
|
|
25
|
+
project := symbolIndexDomainProject(t)
|
|
26
|
+
js := symbolIndexDomainTransform(t, project)
|
|
27
|
+
symbolIndexDomainRunRuntimeCases(t, project, js)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
func symbolIndexDomainProject(t *testing.T) string {
|
|
31
|
+
t.Helper()
|
|
32
|
+
root := ttscTypiaTestRepoRoot(t)
|
|
33
|
+
base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
|
|
34
|
+
if err := os.MkdirAll(base, 0o755); err != nil {
|
|
35
|
+
t.Fatalf("mkdir temp base: %v", err)
|
|
36
|
+
}
|
|
37
|
+
dir, err := os.MkdirTemp(base, "symbol-index-domain-")
|
|
38
|
+
if err != nil {
|
|
39
|
+
t.Fatalf("create temp fixture: %v", err)
|
|
40
|
+
}
|
|
41
|
+
t.Cleanup(func() {
|
|
42
|
+
_ = os.RemoveAll(dir)
|
|
43
|
+
})
|
|
44
|
+
src := filepath.Join(dir, "src")
|
|
45
|
+
if err := os.MkdirAll(src, 0o755); err != nil {
|
|
46
|
+
t.Fatalf("mkdir fixture src: %v", err)
|
|
47
|
+
}
|
|
48
|
+
if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(symbolIndexDomainTSConfig), 0o644); err != nil {
|
|
49
|
+
t.Fatalf("write tsconfig: %v", err)
|
|
50
|
+
}
|
|
51
|
+
if err := os.WriteFile(filepath.Join(src, "main.ts"), []byte(symbolIndexDomainSource), 0o644); err != nil {
|
|
52
|
+
t.Fatalf("write source: %v", err)
|
|
53
|
+
}
|
|
54
|
+
return dir
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
func symbolIndexDomainTransform(t *testing.T, project string) string {
|
|
58
|
+
t.Helper()
|
|
59
|
+
out, errText, code := ttscTypiaTestCapture(func() int {
|
|
60
|
+
return runTransform([]string{
|
|
61
|
+
"--cwd", project,
|
|
62
|
+
"--tsconfig", "tsconfig.json",
|
|
63
|
+
"--file", "src/main.ts",
|
|
64
|
+
"--output", "js",
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
if code != 0 {
|
|
68
|
+
t.Fatalf("symbol index domain transform failed: code=%d stderr=\n%s", code, errText)
|
|
69
|
+
}
|
|
70
|
+
return out
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func symbolIndexDomainRunRuntimeCases(t *testing.T, project string, js string) {
|
|
74
|
+
t.Helper()
|
|
75
|
+
node, err := exec.LookPath("node")
|
|
76
|
+
if err != nil {
|
|
77
|
+
t.Skip("node executable not found")
|
|
78
|
+
}
|
|
79
|
+
runtimeDir := filepath.Join(project, "runtime")
|
|
80
|
+
if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
|
|
81
|
+
t.Fatalf("mkdir runtime dir: %v", err)
|
|
82
|
+
}
|
|
83
|
+
ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
|
|
84
|
+
runtimeJS := ttscTypiaTestRewriteCommonJS(t, js)
|
|
85
|
+
if err := os.WriteFile(filepath.Join(runtimeDir, "main.cjs"), []byte(runtimeJS), 0o644); err != nil {
|
|
86
|
+
t.Fatalf("write runtime module: %v", err)
|
|
87
|
+
}
|
|
88
|
+
runner := filepath.Join(runtimeDir, "run.cjs")
|
|
89
|
+
if err := os.WriteFile(runner, []byte(symbolIndexDomainRuntimeRunner), 0o644); err != nil {
|
|
90
|
+
t.Fatalf("write runtime runner: %v", err)
|
|
91
|
+
}
|
|
92
|
+
cmd := exec.Command(node, runner)
|
|
93
|
+
cmd.Dir = runtimeDir
|
|
94
|
+
if output, err := cmd.CombinedOutput(); err != nil {
|
|
95
|
+
t.Fatalf("symbol index domain runtime cases failed: %v\n%s", err, output)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const symbolIndexDomainTSConfig = `{
|
|
100
|
+
"compilerOptions": {
|
|
101
|
+
"target": "ES2022",
|
|
102
|
+
"module": "commonjs",
|
|
103
|
+
"moduleResolution": "bundler",
|
|
104
|
+
"ignoreDeprecations": "6.0",
|
|
105
|
+
"types": ["*"],
|
|
106
|
+
"esModuleInterop": true,
|
|
107
|
+
"strict": true,
|
|
108
|
+
"skipLibCheck": true
|
|
109
|
+
},
|
|
110
|
+
"include": ["src"]
|
|
111
|
+
}
|
|
112
|
+
`
|
|
113
|
+
|
|
114
|
+
const symbolIndexDomainSource = `import typia from "typia";
|
|
115
|
+
|
|
116
|
+
declare const explicitSymbol: unique symbol;
|
|
117
|
+
|
|
118
|
+
interface SymbolIndex {
|
|
119
|
+
name: string;
|
|
120
|
+
[key: symbol]: number;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
type BrandedSymbol = symbol & {
|
|
124
|
+
readonly __brand: unique symbol;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
interface BrandedSymbolIndex {
|
|
128
|
+
name: string;
|
|
129
|
+
[key: BrandedSymbol]: number;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
interface PlainObject {
|
|
133
|
+
name: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
interface StringIndex {
|
|
137
|
+
name: string;
|
|
138
|
+
[key: string]: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface ExplicitSymbolMember {
|
|
142
|
+
name: string;
|
|
143
|
+
[explicitSymbol]: number;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
type Assert<T extends true> = T;
|
|
147
|
+
type _SymbolIndexHasNoStringDomain = Assert<
|
|
148
|
+
string extends keyof SymbolIndex ? false : true
|
|
149
|
+
>;
|
|
150
|
+
type _SymbolIndexHasNoNumberDomain = Assert<
|
|
151
|
+
number extends keyof SymbolIndex ? false : true
|
|
152
|
+
>;
|
|
153
|
+
type _SymbolIndexHasSymbolDomain = Assert<
|
|
154
|
+
symbol extends keyof SymbolIndex ? true : false
|
|
155
|
+
>;
|
|
156
|
+
type _BrandedSymbolIndexHasNoStringDomain = Assert<
|
|
157
|
+
string extends keyof BrandedSymbolIndex ? false : true
|
|
158
|
+
>;
|
|
159
|
+
type _BrandedSymbolIndexHasNoNumberDomain = Assert<
|
|
160
|
+
number extends keyof BrandedSymbolIndex ? false : true
|
|
161
|
+
>;
|
|
162
|
+
type _BrandedSymbolIndexHasBrandedDomain = Assert<
|
|
163
|
+
BrandedSymbol extends keyof BrandedSymbolIndex ? true : false
|
|
164
|
+
>;
|
|
165
|
+
type _StringIndexHasStringDomain = Assert<
|
|
166
|
+
string extends keyof StringIndex ? true : false
|
|
167
|
+
>;
|
|
168
|
+
type _StringIndexHasNumberDomain = Assert<
|
|
169
|
+
number extends keyof StringIndex ? true : false
|
|
170
|
+
>;
|
|
171
|
+
type _StringIndexHasNoSymbolDomain = Assert<
|
|
172
|
+
symbol extends keyof StringIndex ? false : true
|
|
173
|
+
>;
|
|
174
|
+
type _ExplicitSymbolMemberIsPresent = Assert<
|
|
175
|
+
typeof explicitSymbol extends keyof ExplicitSymbolMember ? true : false
|
|
176
|
+
>;
|
|
177
|
+
|
|
178
|
+
export const isSymbolIndex = typia.createIs<SymbolIndex>();
|
|
179
|
+
export const isBrandedSymbolIndex =
|
|
180
|
+
typia.createIs<BrandedSymbolIndex>();
|
|
181
|
+
export const isPlainObject = typia.createIs<PlainObject>();
|
|
182
|
+
export const isStringIndex = typia.createIs<StringIndex>();
|
|
183
|
+
export const isExplicitSymbolMember =
|
|
184
|
+
typia.createIs<ExplicitSymbolMember>();
|
|
185
|
+
export const schemas = typia.json.schemas<[
|
|
186
|
+
SymbolIndex,
|
|
187
|
+
BrandedSymbolIndex,
|
|
188
|
+
PlainObject,
|
|
189
|
+
StringIndex,
|
|
190
|
+
ExplicitSymbolMember,
|
|
191
|
+
]>();
|
|
192
|
+
`
|
|
193
|
+
|
|
194
|
+
const symbolIndexDomainRuntimeRunner = `const mod = require("./main.cjs");
|
|
195
|
+
|
|
196
|
+
const failures = [];
|
|
197
|
+
const expect = (label, actual, expected) => {
|
|
198
|
+
if (actual !== expected) {
|
|
199
|
+
failures.push(
|
|
200
|
+
label +
|
|
201
|
+
": expected " +
|
|
202
|
+
JSON.stringify(expected) +
|
|
203
|
+
" but got " +
|
|
204
|
+
JSON.stringify(actual),
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
expect("symbol index plain", mod.isSymbolIndex({ name: "x" }), true);
|
|
210
|
+
expect(
|
|
211
|
+
"symbol index ignores a numeric string extra",
|
|
212
|
+
mod.isSymbolIndex({ name: "x", extra: 1 }),
|
|
213
|
+
true,
|
|
214
|
+
);
|
|
215
|
+
expect(
|
|
216
|
+
"symbol index ignores a string extra",
|
|
217
|
+
mod.isSymbolIndex({ name: "x", extra: "unrelated" }),
|
|
218
|
+
true,
|
|
219
|
+
);
|
|
220
|
+
expect(
|
|
221
|
+
"symbol index ignores a matching symbol value",
|
|
222
|
+
mod.isSymbolIndex({ name: "x", [Symbol("key")]: 1 }),
|
|
223
|
+
true,
|
|
224
|
+
);
|
|
225
|
+
expect(
|
|
226
|
+
"symbol index ignores a non-matching symbol value",
|
|
227
|
+
mod.isSymbolIndex({ name: "x", [Symbol("key")]: "outside-json-shape" }),
|
|
228
|
+
true,
|
|
229
|
+
);
|
|
230
|
+
expect("symbol index validates named properties", mod.isSymbolIndex({ name: 1 }), false);
|
|
231
|
+
|
|
232
|
+
expect(
|
|
233
|
+
"branded symbol index plain",
|
|
234
|
+
mod.isBrandedSymbolIndex({ name: "x" }),
|
|
235
|
+
true,
|
|
236
|
+
);
|
|
237
|
+
expect(
|
|
238
|
+
"branded symbol index ignores a string extra",
|
|
239
|
+
mod.isBrandedSymbolIndex({ name: "x", extra: "unrelated" }),
|
|
240
|
+
true,
|
|
241
|
+
);
|
|
242
|
+
expect(
|
|
243
|
+
"branded symbol index ignores a matching symbol value",
|
|
244
|
+
mod.isBrandedSymbolIndex({ name: "x", [Symbol("key")]: 1 }),
|
|
245
|
+
true,
|
|
246
|
+
);
|
|
247
|
+
expect(
|
|
248
|
+
"branded symbol index ignores a non-matching symbol value",
|
|
249
|
+
mod.isBrandedSymbolIndex({ name: "x", [Symbol("key")]: "outside-json-shape" }),
|
|
250
|
+
true,
|
|
251
|
+
);
|
|
252
|
+
expect(
|
|
253
|
+
"branded symbol index validates named properties",
|
|
254
|
+
mod.isBrandedSymbolIndex({ name: 1 }),
|
|
255
|
+
false,
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
expect("plain object ignores a string extra", mod.isPlainObject({ name: "x", extra: 1 }), true);
|
|
259
|
+
expect("plain object validates named properties", mod.isPlainObject({ name: 1 }), false);
|
|
260
|
+
|
|
261
|
+
expect("string index accepts matching extra", mod.isStringIndex({ name: "x", extra: "ok" }), true);
|
|
262
|
+
expect("string index rejects mismatching extra", mod.isStringIndex({ name: "x", extra: 1 }), false);
|
|
263
|
+
|
|
264
|
+
expect(
|
|
265
|
+
"explicit symbol member remains outside the JSON shape",
|
|
266
|
+
mod.isExplicitSymbolMember({ name: "x", [Symbol("member")]: "ignored" }),
|
|
267
|
+
true,
|
|
268
|
+
);
|
|
269
|
+
expect(
|
|
270
|
+
"explicit symbol member validates named properties",
|
|
271
|
+
mod.isExplicitSymbolMember({ name: 1 }),
|
|
272
|
+
false,
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
const schemas = mod.schemas.components.schemas;
|
|
276
|
+
const plain = {
|
|
277
|
+
type: "object",
|
|
278
|
+
properties: { name: { type: "string" } },
|
|
279
|
+
required: ["name"],
|
|
280
|
+
additionalProperties: false,
|
|
281
|
+
};
|
|
282
|
+
const stringIndex = {
|
|
283
|
+
type: "object",
|
|
284
|
+
properties: { name: { type: "string" } },
|
|
285
|
+
required: ["name"],
|
|
286
|
+
additionalProperties: { type: "string" },
|
|
287
|
+
};
|
|
288
|
+
expect(
|
|
289
|
+
"plain object exact schema",
|
|
290
|
+
JSON.stringify(schemas.PlainObject),
|
|
291
|
+
JSON.stringify(plain),
|
|
292
|
+
);
|
|
293
|
+
expect(
|
|
294
|
+
"symbol index exact schema",
|
|
295
|
+
JSON.stringify(schemas.SymbolIndex),
|
|
296
|
+
JSON.stringify(plain),
|
|
297
|
+
);
|
|
298
|
+
expect(
|
|
299
|
+
"branded symbol index exact schema",
|
|
300
|
+
JSON.stringify(schemas.BrandedSymbolIndex),
|
|
301
|
+
JSON.stringify(plain),
|
|
302
|
+
);
|
|
303
|
+
expect(
|
|
304
|
+
"explicit symbol member exact schema",
|
|
305
|
+
JSON.stringify(schemas.ExplicitSymbolMember),
|
|
306
|
+
JSON.stringify(plain),
|
|
307
|
+
);
|
|
308
|
+
expect(
|
|
309
|
+
"string index exact schema",
|
|
310
|
+
JSON.stringify(schemas.StringIndex),
|
|
311
|
+
JSON.stringify(stringIndex),
|
|
312
|
+
);
|
|
313
|
+
if (failures.length !== 0) {
|
|
314
|
+
throw new Error("MISMATCHES:\n" + failures.join("\n"));
|
|
315
|
+
}
|
|
316
|
+
`
|
|
@@ -80,6 +80,8 @@ func runTransform(args []string) int {
|
|
|
80
80
|
return 2
|
|
81
81
|
}
|
|
82
82
|
defer prog.Close()
|
|
83
|
+
registerTypiaDefaultLibraryClassifier(prog)
|
|
84
|
+
defer schemametadata.MetadataDefaultLibrary_release(prog.Checker)
|
|
83
85
|
|
|
84
86
|
transformDiags := []typiaTransformDiagnostic{}
|
|
85
87
|
transformOptions := pluginOptions.TransformOptions()
|
|
@@ -122,6 +124,27 @@ func runTransform(args []string) int {
|
|
|
122
124
|
})
|
|
123
125
|
}
|
|
124
126
|
|
|
127
|
+
// registerTypiaDefaultLibraryClassifier hands metadata analysis the program's
|
|
128
|
+
// own default-library classification, which runtime-native identity is decided
|
|
129
|
+
// from: a global is the JavaScript built-in only when a runtime authority
|
|
130
|
+
// declares it (#2200). `prog.TSProgram.IsLibFile` is the same oracle the
|
|
131
|
+
// dependency collector above uses, and for the same reason — a default library
|
|
132
|
+
// is not recognizable from its file name under `bundled:///`, `noembed`, or
|
|
133
|
+
// `libReplacement` (#2108).
|
|
134
|
+
//
|
|
135
|
+
// Every program-loading host registers it against the checker whose types the
|
|
136
|
+
// analysis reads, and releases it when that program closes, so no closed
|
|
137
|
+
// program's checker stays reachable from the registry.
|
|
138
|
+
func registerTypiaDefaultLibraryClassifier(prog *driver.Program) {
|
|
139
|
+
if prog == nil || prog.TSProgram == nil {
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
program := prog.TSProgram
|
|
143
|
+
schemametadata.MetadataDefaultLibrary_register(prog.Checker, func(source *shimast.SourceFile) bool {
|
|
144
|
+
return source != nil && program.IsLibFile(source)
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
125
148
|
// runTransformSingle is the single-file counterpart of runTransformProject's
|
|
126
149
|
// diagnostic decision: produce the artifact into memory, then publish it only
|
|
127
150
|
// when typia's analysis reported nothing. Every single-file output mode routes
|
|
@@ -6,6 +6,7 @@ import (
|
|
|
6
6
|
"os/exec"
|
|
7
7
|
"path/filepath"
|
|
8
8
|
"runtime"
|
|
9
|
+
"sort"
|
|
9
10
|
"strings"
|
|
10
11
|
"testing"
|
|
11
12
|
)
|
|
@@ -68,6 +69,11 @@ func ttscTypiaTestWriteCommonRuntimeStubs(t *testing.T, runtimeDir string) {
|
|
|
68
69
|
"access-expression-stub.cjs": ttscTypiaTestAccessExpressionStub,
|
|
69
70
|
"string-length-stub.cjs": ttscTypiaTestStringLengthStub,
|
|
70
71
|
"notation-stub.cjs": ttscTypiaTestNotationStub,
|
|
72
|
+
"json-stringify-array-stub.cjs": ttscTypiaTestJsonStringifyArrayStub,
|
|
73
|
+
"json-stringify-property-stub.cjs": ttscTypiaTestJsonStringifyPropertyStub,
|
|
74
|
+
"json-stringify-element-stub.cjs": ttscTypiaTestJsonStringifyElementStub,
|
|
75
|
+
"json-stringify-tail-stub.cjs": ttscTypiaTestJsonStringifyTailStub,
|
|
76
|
+
"random-string-stub.cjs": ttscTypiaTestRandomStringStub,
|
|
71
77
|
}
|
|
72
78
|
for name, content := range files {
|
|
73
79
|
if err := os.WriteFile(filepath.Join(runtimeDir, name), []byte(content), 0o644); err != nil {
|
|
@@ -85,6 +91,11 @@ func ttscTypiaTestRewriteCommonJS(t *testing.T, js string) string {
|
|
|
85
91
|
runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_functionalTypeGuardErrorFactory")`, `require("./functional-error-stub.cjs")`)
|
|
86
92
|
runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_accessExpressionAsString")`, `require("./access-expression-stub.cjs")`)
|
|
87
93
|
runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_stringLength")`, `require("./string-length-stub.cjs")`)
|
|
94
|
+
runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_jsonStringifyArray")`, `require("./json-stringify-array-stub.cjs")`)
|
|
95
|
+
runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_jsonStringifyProperty")`, `require("./json-stringify-property-stub.cjs")`)
|
|
96
|
+
runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_jsonStringifyElement")`, `require("./json-stringify-element-stub.cjs")`)
|
|
97
|
+
runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_jsonStringifyTail")`, `require("./json-stringify-tail-stub.cjs")`)
|
|
98
|
+
runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_randomString")`, `require("./random-string-stub.cjs")`)
|
|
88
99
|
for _, helper := range []string{"_notationAssign", "_notationCamel", "_notationKebab", "_notationKeyCollision", "_notationPascal", "_notationSnake"} {
|
|
89
100
|
runtimeJS = strings.ReplaceAll(
|
|
90
101
|
runtimeJS,
|
|
@@ -93,9 +104,29 @@ func ttscTypiaTestRewriteCommonJS(t *testing.T, js string) string {
|
|
|
93
104
|
)
|
|
94
105
|
}
|
|
95
106
|
for _, needle := range []string{`require("typia")`, `require('typia')`, `from "typia"`, `from 'typia'`, `typia/lib/internal/`} {
|
|
96
|
-
if strings.Contains(runtimeJS, needle) {
|
|
97
|
-
|
|
107
|
+
if !strings.Contains(runtimeJS, needle) {
|
|
108
|
+
continue
|
|
98
109
|
}
|
|
110
|
+
// Name the modules that are actually unmapped. Reporting only the needle
|
|
111
|
+
// makes every new internal helper look like the same failure and sends the
|
|
112
|
+
// reader hunting through the emit for it.
|
|
113
|
+
if needle == `typia/lib/internal/` {
|
|
114
|
+
unresolved := map[string]bool{}
|
|
115
|
+
for _, part := range strings.Split(runtimeJS, needle)[1:] {
|
|
116
|
+
end := strings.IndexAny(part, "\"')")
|
|
117
|
+
if end < 0 {
|
|
118
|
+
end = len(part)
|
|
119
|
+
}
|
|
120
|
+
unresolved[part[:end]] = true
|
|
121
|
+
}
|
|
122
|
+
names := make([]string, 0, len(unresolved))
|
|
123
|
+
for name := range unresolved {
|
|
124
|
+
names = append(names, name)
|
|
125
|
+
}
|
|
126
|
+
sort.Strings(names)
|
|
127
|
+
t.Fatalf("runtime module has no stub for typia internal helpers: %s", strings.Join(names, ", "))
|
|
128
|
+
}
|
|
129
|
+
t.Fatalf("runtime module still contains unresolved typia import %q", needle)
|
|
99
130
|
}
|
|
100
131
|
return runtimeJS
|
|
101
132
|
}
|
|
@@ -142,6 +173,50 @@ const ttscTypiaTestFunctionalErrorStub = `module.exports._functionalTypeGuardErr
|
|
|
142
173
|
Object.assign(new Error(props.expected), props);
|
|
143
174
|
`
|
|
144
175
|
|
|
176
|
+
// The two JSON stringify stubs mirror packages/typia/src/internal exactly. They
|
|
177
|
+
// are runtime doubles for the emit these tests execute; the shipped helpers
|
|
178
|
+
// themselves are exercised by the TypeScript suites against the real package.
|
|
179
|
+
const ttscTypiaTestJsonStringifyArrayStub = `module.exports._jsonStringifyArray = (elements, mapper) => {
|
|
180
|
+
const length = Math.min(
|
|
181
|
+
Math.max(Math.trunc(elements.length) || 0, 0),
|
|
182
|
+
Number.MAX_SAFE_INTEGER,
|
|
183
|
+
);
|
|
184
|
+
let output = "";
|
|
185
|
+
for (let i = 0; i < length; ++i) {
|
|
186
|
+
const elem = elements[i];
|
|
187
|
+
const text = elem === undefined ? undefined : mapper(elem, i);
|
|
188
|
+
output += (i === 0 ? "" : ",") + (text === undefined ? "null" : text);
|
|
189
|
+
}
|
|
190
|
+
return output;
|
|
191
|
+
};
|
|
192
|
+
`
|
|
193
|
+
|
|
194
|
+
const ttscTypiaTestJsonStringifyPropertyStub = `module.exports._jsonStringifyProperty = (head, text, tail) =>
|
|
195
|
+
text === undefined ? "" : head + text + tail;
|
|
196
|
+
`
|
|
197
|
+
|
|
198
|
+
const ttscTypiaTestJsonStringifyElementStub = `module.exports._jsonStringifyElement = (text) =>
|
|
199
|
+
text === undefined ? "null" : text;
|
|
200
|
+
`
|
|
201
|
+
|
|
202
|
+
// Deterministic rather than random: these runtimes assert observable behavior
|
|
203
|
+
// of the emitted validators, so a generated string only has to satisfy the
|
|
204
|
+
// declared bounds, and a stable one keeps a failure reproducible.
|
|
205
|
+
const ttscTypiaTestJsonStringifyTailStub = `module.exports._jsonStringifyTail = (str) =>
|
|
206
|
+
str[str.length - 1] === "," ? str.substring(0, str.length - 1) : str;
|
|
207
|
+
`
|
|
208
|
+
|
|
209
|
+
const ttscTypiaTestRandomStringStub = `module.exports._randomString = (props) => {
|
|
210
|
+
const minimum =
|
|
211
|
+
props.minLength !== undefined
|
|
212
|
+
? props.minLength
|
|
213
|
+
: Math.min(props.maxLength !== undefined ? props.maxLength : 5, 5);
|
|
214
|
+
const maximum = props.maxLength !== undefined ? props.maxLength : minimum + 5;
|
|
215
|
+
const length = Math.max(minimum, Math.min(minimum, maximum));
|
|
216
|
+
return "a".repeat(length);
|
|
217
|
+
};
|
|
218
|
+
`
|
|
219
|
+
|
|
145
220
|
const ttscTypiaTestStringLengthStub = `module.exports._stringLength = (value) => {
|
|
146
221
|
let count = 0;
|
|
147
222
|
for (const _ of value) ++count;
|