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
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { _randomInteger } from "./_randomInteger";
|
|
1
2
|
import { _randomString } from "./_randomString";
|
|
2
3
|
|
|
4
|
+
export const _RANDOM_LENGTH_ERROR =
|
|
5
|
+
"unable to generate a random string satisfying both the format and the length constraints.";
|
|
6
|
+
|
|
3
7
|
/**
|
|
4
8
|
* Length bounds forwarded to a string format or pattern generator.
|
|
5
9
|
*
|
|
@@ -18,10 +22,10 @@ export interface _ILengthProps {
|
|
|
18
22
|
* length `fixed + segment.length` lands inside the requested window.
|
|
19
23
|
*
|
|
20
24
|
* `fixed` is the number of characters the format always contributes around the
|
|
21
|
-
* segment, `fallback` is the segment length used when the leaf is
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
+
* segment, `fallback` is the segment length used when the leaf is unconstrained
|
|
26
|
+
* on that side, and `minimum` is the smallest segment the format still
|
|
27
|
+
* validates with. Throws when the window cannot be satisfied by this format's
|
|
28
|
+
* shape (e.g. `Format<"email"> & MaxLength<3>`).
|
|
25
29
|
*/
|
|
26
30
|
export const _randomSegmentLength = (
|
|
27
31
|
props: _ILengthProps | undefined,
|
|
@@ -36,21 +40,63 @@ export const _randomSegmentLength = (
|
|
|
36
40
|
// characters so the generated length varies, mirroring `_randomString`.
|
|
37
41
|
const high: number =
|
|
38
42
|
props?.maxLength === undefined ? low + fallback : props.maxLength - fixed;
|
|
39
|
-
if (high < low || high < minimum)
|
|
40
|
-
throw new Error(
|
|
41
|
-
"unable to generate a random string satisfying both the format and the length constraints.",
|
|
42
|
-
);
|
|
43
|
+
if (high < low || high < minimum) throw new Error(_RANDOM_LENGTH_ERROR);
|
|
43
44
|
return _randomString({ type: "string", minLength: low, maxLength: high });
|
|
44
45
|
};
|
|
45
46
|
|
|
46
47
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
48
|
+
* Intersects the requested length window with the lengths a format's grammar
|
|
49
|
+
* can express, and draws one of them.
|
|
50
|
+
*
|
|
51
|
+
* `minimum` and `maximum` are the shortest and longest values the format admits
|
|
52
|
+
* — omit `maximum` when the grammar is open above — and `spread` is how far
|
|
53
|
+
* past the floor an unbounded request may reach, so an open side still varies
|
|
54
|
+
* the way `_randomString` does. The caller draws from the returned window and
|
|
55
|
+
* applies whatever step its grammar has (base64 lengths are multiples of four,
|
|
56
|
+
* a fractional second needs at least one digit).
|
|
57
|
+
*
|
|
58
|
+
* Throws only when the window and the grammar do not overlap at all. That is
|
|
59
|
+
* the distinction the retry driver below cannot make: it redraws one shape, so
|
|
60
|
+
* it gives up on every length that shape never emits even when the format
|
|
61
|
+
* itself accepts one (issue #2284).
|
|
62
|
+
*/
|
|
63
|
+
export const _randomLengthWindow = (
|
|
64
|
+
props: _ILengthProps | undefined,
|
|
65
|
+
format: { minimum: number; maximum?: number; spread?: number },
|
|
66
|
+
): { low: number; high: number } => {
|
|
67
|
+
const ceiling: number = format.maximum ?? Number.MAX_SAFE_INTEGER;
|
|
68
|
+
const low: number = Math.max(
|
|
69
|
+
props?.minLength ?? format.minimum,
|
|
70
|
+
format.minimum,
|
|
71
|
+
);
|
|
72
|
+
const high: number = Math.min(
|
|
73
|
+
props?.maxLength ?? low + (format.spread ?? 0),
|
|
74
|
+
ceiling,
|
|
75
|
+
);
|
|
76
|
+
if (low > high) throw new Error(_RANDOM_LENGTH_ERROR);
|
|
77
|
+
return { low, high };
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** Draws a length inside a window produced by {@link _randomLengthWindow}. */
|
|
81
|
+
export const _randomLengthPick = (window: {
|
|
82
|
+
low: number;
|
|
83
|
+
high: number;
|
|
84
|
+
}): number =>
|
|
85
|
+
_randomInteger({
|
|
86
|
+
type: "integer",
|
|
87
|
+
minimum: window.low,
|
|
88
|
+
maximum: window.high,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Wraps a fixed-length format generator (uuid, date) with the requested length
|
|
93
|
+
* window.
|
|
49
94
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
95
|
+
* Use it only where the grammar admits exactly one length, so a window that
|
|
96
|
+
* excludes it is genuinely unsatisfiable. A format that can express more than
|
|
97
|
+
* one length must build its value at a length drawn from
|
|
98
|
+
* {@link _randomLengthWindow} instead; redrawing one shape cannot reach a length
|
|
99
|
+
* that shape never emits.
|
|
54
100
|
*/
|
|
55
101
|
export const _randomFormatLength = (
|
|
56
102
|
props: _ILengthProps | undefined,
|
|
@@ -66,7 +112,5 @@ export const _randomFormatLength = (
|
|
|
66
112
|
)
|
|
67
113
|
return value;
|
|
68
114
|
}
|
|
69
|
-
throw new Error(
|
|
70
|
-
"unable to generate a random string satisfying both the format and the length constraints.",
|
|
71
|
-
);
|
|
115
|
+
throw new Error(_RANDOM_LENGTH_ERROR);
|
|
72
116
|
};
|
|
@@ -9,10 +9,7 @@
|
|
|
9
9
|
* collapsing it to the underscore-free `plain` path.
|
|
10
10
|
*/
|
|
11
11
|
export const __notationRename =
|
|
12
|
-
(props: {
|
|
13
|
-
plain: (str: string) => string;
|
|
14
|
-
snake: (str: string) => string;
|
|
15
|
-
}) =>
|
|
12
|
+
(props: { plain: (str: string) => string; snake: (str: string) => string }) =>
|
|
16
13
|
(str: string): string => {
|
|
17
14
|
let prefix: string = "";
|
|
18
15
|
while (str.startsWith("_")) {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { _randomInteger } from "../_randomInteger";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Splits `total` into `count` parts, each inside `[minimum, maximum]`.
|
|
5
|
+
*
|
|
6
|
+
* Used where a format's length is the sum of its segments — an IPv4 octet spans
|
|
7
|
+
* one to three digits, an IPv6 group one to four — so a requested total length
|
|
8
|
+
* is realized by choosing how many characters each segment contributes instead
|
|
9
|
+
* of redrawing whole addresses and hoping one lands in the window (issue
|
|
10
|
+
* #2284).
|
|
11
|
+
*
|
|
12
|
+
* The caller guarantees `count * minimum <= total <= count * maximum`; each
|
|
13
|
+
* part is drawn from the range that still leaves the remaining parts
|
|
14
|
+
* satisfiable.
|
|
15
|
+
*/
|
|
16
|
+
export const __randomComposition = (props: {
|
|
17
|
+
total: number;
|
|
18
|
+
count: number;
|
|
19
|
+
minimum: number;
|
|
20
|
+
maximum: number;
|
|
21
|
+
}): number[] => {
|
|
22
|
+
const parts: number[] = [];
|
|
23
|
+
let remaining: number = props.total;
|
|
24
|
+
for (let i: number = 0; i < props.count; ++i) {
|
|
25
|
+
const rest: number = props.count - i - 1;
|
|
26
|
+
const value: number = _randomInteger({
|
|
27
|
+
type: "integer",
|
|
28
|
+
minimum: Math.max(props.minimum, remaining - rest * props.maximum),
|
|
29
|
+
maximum: Math.min(props.maximum, remaining - rest * props.minimum),
|
|
30
|
+
});
|
|
31
|
+
parts.push(value);
|
|
32
|
+
remaining -= value;
|
|
33
|
+
}
|
|
34
|
+
return parts;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** Draws `length` decimal digits, leading zeros included. */
|
|
38
|
+
export const __randomDigits = (length: number): string => {
|
|
39
|
+
let text: string = "";
|
|
40
|
+
for (let i: number = 0; i < length; ++i)
|
|
41
|
+
text += String(_randomInteger({ type: "integer", minimum: 0, maximum: 9 }));
|
|
42
|
+
return text;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** Draws a decimal number of exactly `length` digits without a leading zero. */
|
|
46
|
+
export const __randomNumeric = (length: number): string =>
|
|
47
|
+
length <= 1
|
|
48
|
+
? String(_randomInteger({ type: "integer", minimum: 0, maximum: 9 }))
|
|
49
|
+
: String(_randomInteger({ type: "integer", minimum: 1, maximum: 9 })) +
|
|
50
|
+
__randomDigits(length - 1);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { _randomInteger } from "../_randomInteger";
|
|
2
|
+
|
|
3
|
+
export interface __IEpochProps {
|
|
4
|
+
minimum?: number;
|
|
5
|
+
maximum?: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Draws an epoch millisecond inside the requested bounds.
|
|
10
|
+
*
|
|
11
|
+
* Shared by the `date` and `date-time` generators, which had the same bound
|
|
12
|
+
* expression written twice: `props?.maximum ?? props?.minimum === undefined`
|
|
13
|
+
* parses as `props?.maximum ?? (props?.minimum === undefined)` because `??`
|
|
14
|
+
* binds looser than `===`, so any supplied `maximum` made the condition truthy
|
|
15
|
+
* and was replaced by `Date.now()`, while `maximum: 0` fell through to
|
|
16
|
+
* `undefined + one year` and produced `NaN` (issue #2287). Keeping the
|
|
17
|
+
* resolution in one place is what stops the two copies from drifting again.
|
|
18
|
+
*
|
|
19
|
+
* With no bound at all the window ends at the present instant; with only a
|
|
20
|
+
* lower bound it spans one year from there.
|
|
21
|
+
*/
|
|
22
|
+
export const __randomEpoch = (props?: __IEpochProps): number => {
|
|
23
|
+
const minimum: number = props?.minimum ?? 0;
|
|
24
|
+
const maximum: number =
|
|
25
|
+
props?.maximum ??
|
|
26
|
+
(props?.minimum === undefined ? Date.now() : props.minimum + YEAR);
|
|
27
|
+
return _randomInteger({
|
|
28
|
+
type: "integer",
|
|
29
|
+
minimum,
|
|
30
|
+
maximum,
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const YEAR = 365 * 24 * 60 * 60 * 1_000;
|
package/native/adapter/visit.go
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
package adapter
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"path/filepath"
|
|
5
|
-
"strings"
|
|
6
|
-
|
|
7
|
-
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
8
|
-
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
type CallSite struct {
|
|
12
|
-
File *shimast.SourceFile
|
|
13
|
-
FilePath string
|
|
14
|
-
Module string
|
|
15
|
-
Method string
|
|
16
|
-
Call *shimast.CallExpression
|
|
17
|
-
RootName string
|
|
18
|
-
Namespaces []string
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
func CollectCallSites(files []*shimast.SourceFile, checker *shimchecker.Checker) []CallSite {
|
|
22
|
-
sites := []CallSite{}
|
|
23
|
-
for _, file := range files {
|
|
24
|
-
if file == nil || file.IsDeclarationFile {
|
|
25
|
-
continue
|
|
26
|
-
}
|
|
27
|
-
file.ForEachChild(func(node *shimast.Node) bool {
|
|
28
|
-
visitCallSite(file, checker, node, &sites)
|
|
29
|
-
return false
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
return sites
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
func visitCallSite(file *shimast.SourceFile, checker *shimchecker.Checker, node *shimast.Node, sites *[]CallSite) {
|
|
36
|
-
if node == nil {
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
if node.Kind == shimast.KindCallExpression {
|
|
40
|
-
if site, ok := tryCallSite(file, checker, node); ok {
|
|
41
|
-
*sites = append(*sites, site)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
node.ForEachChild(func(child *shimast.Node) bool {
|
|
45
|
-
visitCallSite(file, checker, child, sites)
|
|
46
|
-
return false
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
func tryCallSite(file *shimast.SourceFile, checker *shimchecker.Checker, node *shimast.Node) (CallSite, bool) {
|
|
51
|
-
if checker == nil {
|
|
52
|
-
return CallSite{}, false
|
|
53
|
-
}
|
|
54
|
-
if node.Kind != shimast.KindCallExpression {
|
|
55
|
-
return CallSite{}, false
|
|
56
|
-
}
|
|
57
|
-
call := node.AsCallExpression()
|
|
58
|
-
if call == nil {
|
|
59
|
-
return CallSite{}, false
|
|
60
|
-
}
|
|
61
|
-
signature := checker.GetResolvedSignature(node)
|
|
62
|
-
if signature == nil {
|
|
63
|
-
return CallSite{}, false
|
|
64
|
-
}
|
|
65
|
-
declaration := signature.Declaration()
|
|
66
|
-
if declaration == nil {
|
|
67
|
-
return CallSite{}, false
|
|
68
|
-
}
|
|
69
|
-
sourceFile := shimast.GetSourceFileOfNode(declaration)
|
|
70
|
-
if sourceFile == nil {
|
|
71
|
-
return CallSite{}, false
|
|
72
|
-
}
|
|
73
|
-
module, ok := matchTypiaModule(sourceFile.FileName())
|
|
74
|
-
if !ok {
|
|
75
|
-
return CallSite{}, false
|
|
76
|
-
}
|
|
77
|
-
method := callSiteMethodName(checker, declaration, call)
|
|
78
|
-
if method == "" {
|
|
79
|
-
return CallSite{}, false
|
|
80
|
-
}
|
|
81
|
-
root, namespaces, ok := extractRootAndNamespaces(call, method)
|
|
82
|
-
if !ok {
|
|
83
|
-
return CallSite{}, false
|
|
84
|
-
}
|
|
85
|
-
return CallSite{
|
|
86
|
-
File: file,
|
|
87
|
-
FilePath: file.FileName(),
|
|
88
|
-
Module: module,
|
|
89
|
-
Method: method,
|
|
90
|
-
Call: call,
|
|
91
|
-
RootName: root,
|
|
92
|
-
Namespaces: namespaces,
|
|
93
|
-
}, true
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
func matchTypiaModule(location string) (string, bool) {
|
|
97
|
-
location = filepath.ToSlash(location)
|
|
98
|
-
for _, suffix := range []string{".d.ts", ".ts"} {
|
|
99
|
-
for _, middle := range []string{"typia/lib/", "typia/src/", "packages/typia/src/"} {
|
|
100
|
-
index := strings.LastIndex(location, middle)
|
|
101
|
-
if index < 0 {
|
|
102
|
-
continue
|
|
103
|
-
}
|
|
104
|
-
name := location[index+len(middle):]
|
|
105
|
-
if !strings.HasSuffix(name, suffix) {
|
|
106
|
-
continue
|
|
107
|
-
}
|
|
108
|
-
name = strings.TrimSuffix(name, suffix)
|
|
109
|
-
if strings.Contains(name, "/") {
|
|
110
|
-
continue
|
|
111
|
-
}
|
|
112
|
-
return name, true
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return "", false
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
func callSiteMethodName(checker *shimchecker.Checker, declaration *shimast.Node, call *shimast.CallExpression) string {
|
|
119
|
-
if name := declaration.Name(); name != nil {
|
|
120
|
-
if checker != nil {
|
|
121
|
-
if symbol := checker.GetSymbolAtLocation(name); symbol != nil && symbol.Name != "" {
|
|
122
|
-
return symbol.Name
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
if name.Kind == shimast.KindIdentifier {
|
|
126
|
-
if id := name.AsIdentifier(); id != nil {
|
|
127
|
-
return id.Text
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if call.Expression != nil && call.Expression.Kind == shimast.KindPropertyAccessExpression {
|
|
132
|
-
if property := call.Expression.AsPropertyAccessExpression(); property != nil {
|
|
133
|
-
if name := property.Name(); name != nil && name.Kind == shimast.KindIdentifier {
|
|
134
|
-
if id := name.AsIdentifier(); id != nil {
|
|
135
|
-
return id.Text
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
return ""
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
func extractRootAndNamespaces(call *shimast.CallExpression, method string) (string, []string, bool) {
|
|
144
|
-
expression := call.Expression
|
|
145
|
-
segments := []string{}
|
|
146
|
-
for expression != nil && expression.Kind == shimast.KindPropertyAccessExpression {
|
|
147
|
-
property := expression.AsPropertyAccessExpression()
|
|
148
|
-
if property == nil {
|
|
149
|
-
break
|
|
150
|
-
}
|
|
151
|
-
name := property.Name()
|
|
152
|
-
if name == nil || name.Kind != shimast.KindIdentifier {
|
|
153
|
-
return "", nil, false
|
|
154
|
-
}
|
|
155
|
-
id := name.AsIdentifier()
|
|
156
|
-
if id == nil || id.Text == "" {
|
|
157
|
-
return "", nil, false
|
|
158
|
-
}
|
|
159
|
-
segments = append([]string{id.Text}, segments...)
|
|
160
|
-
expression = property.Expression
|
|
161
|
-
}
|
|
162
|
-
if expression == nil || expression.Kind != shimast.KindIdentifier {
|
|
163
|
-
return "", nil, false
|
|
164
|
-
}
|
|
165
|
-
root := expression.AsIdentifier()
|
|
166
|
-
if root == nil || root.Text == "" || len(segments) == 0 {
|
|
167
|
-
return "", nil, false
|
|
168
|
-
}
|
|
169
|
-
if segments[len(segments)-1] != method {
|
|
170
|
-
return "", nil, false
|
|
171
|
-
}
|
|
172
|
-
return root.Text, segments[:len(segments)-1], true
|
|
173
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
//go:build typia_native_internal
|
|
2
|
-
// +build typia_native_internal
|
|
3
|
-
|
|
4
|
-
package adapter
|
|
5
|
-
|
|
6
|
-
import (
|
|
7
|
-
"path/filepath"
|
|
8
|
-
"testing"
|
|
9
|
-
|
|
10
|
-
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
11
|
-
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
12
|
-
shimcore "github.com/microsoft/typescript-go/shim/core"
|
|
13
|
-
shimparser "github.com/microsoft/typescript-go/shim/parser"
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
// TestVisitPropertyChainEdges verifies call-site property-chain parsing.
|
|
17
|
-
//
|
|
18
|
-
// Call-site discovery peels a TypeScript expression like
|
|
19
|
-
// `typia.json.stringify()` into a root import name, namespace chain, and method.
|
|
20
|
-
// Malformed or mismatched chains must be rejected without producing a site.
|
|
21
|
-
//
|
|
22
|
-
// 1. Build a nested property-access call expression.
|
|
23
|
-
// 2. Extract the root name, namespace, and terminal method.
|
|
24
|
-
// 3. Reject a method mismatch, a non-property call, and an empty member name.
|
|
25
|
-
// 4. Verify nil nodes do not append call sites.
|
|
26
|
-
func TestVisitPropertyChainEdges(t *testing.T) {
|
|
27
|
-
factory := shimast.NewNodeFactory(shimast.NodeFactoryHooks{})
|
|
28
|
-
namespace := factory.NewPropertyAccessExpression(
|
|
29
|
-
factory.NewIdentifier("typia"),
|
|
30
|
-
nil,
|
|
31
|
-
factory.NewIdentifier("json"),
|
|
32
|
-
shimast.NodeFlagsNone,
|
|
33
|
-
)
|
|
34
|
-
method := factory.NewPropertyAccessExpression(
|
|
35
|
-
namespace,
|
|
36
|
-
nil,
|
|
37
|
-
factory.NewIdentifier("stringify"),
|
|
38
|
-
shimast.NodeFlagsNone,
|
|
39
|
-
)
|
|
40
|
-
call := factory.NewCallExpression(method, nil, nil, factory.NewNodeList(nil), shimast.NodeFlagsNone).AsCallExpression()
|
|
41
|
-
|
|
42
|
-
root, namespaces, ok := extractRootAndNamespaces(call, "stringify")
|
|
43
|
-
if !ok || root != "typia" || len(namespaces) != 1 || namespaces[0] != "json" {
|
|
44
|
-
t.Fatalf("unexpected property-chain extraction: root=%q namespaces=%#v ok=%v", root, namespaces, ok)
|
|
45
|
-
}
|
|
46
|
-
if _, _, ok := extractRootAndNamespaces(call, "is"); ok {
|
|
47
|
-
t.Fatal("method mismatch should reject the call chain")
|
|
48
|
-
}
|
|
49
|
-
statement := factory.NewExpressionStatement(factory.NewIdentifier("noop"))
|
|
50
|
-
if method := callSiteMethodName(nil, statement, call); method != "stringify" {
|
|
51
|
-
t.Fatalf("property-access method fallback mismatch: %q", method)
|
|
52
|
-
}
|
|
53
|
-
declaration := factory.NewFunctionDeclaration(
|
|
54
|
-
nil,
|
|
55
|
-
nil,
|
|
56
|
-
factory.NewIdentifier("declared"),
|
|
57
|
-
nil,
|
|
58
|
-
nil,
|
|
59
|
-
nil,
|
|
60
|
-
nil,
|
|
61
|
-
nil,
|
|
62
|
-
)
|
|
63
|
-
if method := callSiteMethodName(nil, declaration, call); method != "declared" {
|
|
64
|
-
t.Fatalf("declaration-name fallback mismatch: %q", method)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
plain := factory.NewCallExpression(
|
|
68
|
-
factory.NewIdentifier("plain"),
|
|
69
|
-
nil,
|
|
70
|
-
nil,
|
|
71
|
-
factory.NewNodeList(nil),
|
|
72
|
-
shimast.NodeFlagsNone,
|
|
73
|
-
).AsCallExpression()
|
|
74
|
-
if _, _, ok := extractRootAndNamespaces(plain, "plain"); ok {
|
|
75
|
-
t.Fatal("plain calls without a property chain should be rejected")
|
|
76
|
-
}
|
|
77
|
-
literal := factory.NewCallExpression(
|
|
78
|
-
factory.NewStringLiteral("call", shimast.TokenFlagsNone),
|
|
79
|
-
nil,
|
|
80
|
-
nil,
|
|
81
|
-
factory.NewNodeList(nil),
|
|
82
|
-
shimast.NodeFlagsNone,
|
|
83
|
-
).AsCallExpression()
|
|
84
|
-
if _, _, ok := extractRootAndNamespaces(literal, "call"); ok {
|
|
85
|
-
t.Fatal("non-identifier root expressions should be rejected")
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
emptyMember := factory.NewPropertyAccessExpression(
|
|
89
|
-
factory.NewIdentifier("typia"),
|
|
90
|
-
nil,
|
|
91
|
-
factory.NewIdentifier(""),
|
|
92
|
-
shimast.NodeFlagsNone,
|
|
93
|
-
)
|
|
94
|
-
emptyCall := factory.NewCallExpression(emptyMember, nil, nil, factory.NewNodeList(nil), shimast.NodeFlagsNone).AsCallExpression()
|
|
95
|
-
if _, _, ok := extractRootAndNamespaces(emptyCall, ""); ok {
|
|
96
|
-
t.Fatal("empty property name should be rejected")
|
|
97
|
-
}
|
|
98
|
-
stringMember := factory.NewPropertyAccessExpression(
|
|
99
|
-
factory.NewIdentifier("typia"),
|
|
100
|
-
nil,
|
|
101
|
-
factory.NewStringLiteral("is", shimast.TokenFlagsNone),
|
|
102
|
-
shimast.NodeFlagsNone,
|
|
103
|
-
)
|
|
104
|
-
stringMemberCall := factory.NewCallExpression(stringMember, nil, nil, factory.NewNodeList(nil), shimast.NodeFlagsNone).AsCallExpression()
|
|
105
|
-
if _, _, ok := extractRootAndNamespaces(stringMemberCall, "is"); ok {
|
|
106
|
-
t.Fatal("non-identifier property names should be rejected")
|
|
107
|
-
}
|
|
108
|
-
sites := []CallSite{}
|
|
109
|
-
visitCallSite(nil, nil, nil, &sites)
|
|
110
|
-
if len(sites) != 0 {
|
|
111
|
-
t.Fatalf("nil node should not append call sites: %#v", sites)
|
|
112
|
-
}
|
|
113
|
-
file := shimparser.ParseSourceFile(
|
|
114
|
-
shimast.SourceFileParseOptions{FileName: filepath.ToSlash(filepath.Join(t.TempDir(), "visit.ts"))},
|
|
115
|
-
`typia.is(input);`,
|
|
116
|
-
shimcore.ScriptKindTS,
|
|
117
|
-
)
|
|
118
|
-
declFile := *file
|
|
119
|
-
declFile.IsDeclarationFile = true
|
|
120
|
-
if sites := CollectCallSites([]*shimast.SourceFile{nil, &declFile}, nil); len(sites) != 0 {
|
|
121
|
-
t.Fatalf("nil and declaration files should not produce call sites: %#v", sites)
|
|
122
|
-
}
|
|
123
|
-
if _, ok := tryCallSite(file, nil, call.AsNode()); ok {
|
|
124
|
-
t.Fatal("nil checker should reject call-site probing")
|
|
125
|
-
}
|
|
126
|
-
if _, ok := tryCallSite(file, &shimchecker.Checker{}, statement); ok {
|
|
127
|
-
t.Fatal("non-call nodes should reject call-site probing")
|
|
128
|
-
}
|
|
129
|
-
}
|