@zyno-io/ts-reflection 26.913.2245 → 26.914.1839
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/dist/reflection/compact-metadata.d.ts +11 -0
- package/dist/reflection/compact-metadata.d.ts.map +1 -1
- package/dist/type-compiler/go/compact_metadata.go +280 -25
- package/dist/type-compiler/go/emission_plan.go +153 -9
- package/dist/type-compiler/go/emit_ast.go +1 -0
- package/dist/type-compiler/go/emit_ast_test.go +112 -0
- package/dist/type-metadata-runtime.cjs +1 -1
- package/dist/type-metadata-runtime.js +121 -34
- package/package.json +1 -1
|
@@ -11,8 +11,19 @@
|
|
|
11
11
|
* instead of being decoded with different semantics.
|
|
12
12
|
*/
|
|
13
13
|
export declare function decodeCompactMetadataV1<T>(serialized: string, references: readonly unknown[], resolveType?: (index: number) => unknown): T;
|
|
14
|
+
/**
|
|
15
|
+
* Lazily reconstruct metadata serialized by the native type compiler.
|
|
16
|
+
*
|
|
17
|
+
* V2 stores repeated object and array subtrees in a graph table. The returned
|
|
18
|
+
* proxy intentionally does not parse that table until metadata is inspected.
|
|
19
|
+
* Compiler-generated assignments such as `metadata.classType = Target` are
|
|
20
|
+
* retained as overrides and therefore do not force eager materialization.
|
|
21
|
+
*/
|
|
22
|
+
export declare function decodeCompactMetadataV2<T extends object>(serialized: string, references: readonly unknown[], resolveType?: (index: number) => unknown): T;
|
|
14
23
|
/** Create one lazy metadata-type registry for a generated module. */
|
|
15
24
|
export declare function createCompactMetadataRegistryV1(serialized: string, references: readonly unknown[]): (index: number) => unknown;
|
|
25
|
+
/** Create one fully lazy V2 metadata-type registry for a generated module. */
|
|
26
|
+
export declare function createCompactMetadataRegistryV2(serialized: string, references: readonly unknown[]): (index: number) => unknown;
|
|
16
27
|
/** Resolve metadata published by a type-only external import at first use. */
|
|
17
28
|
export declare function resolveCompactMetadataAliasV1(loadModule: (() => unknown) | ((specifier: string) => unknown), specifierOrExportName: string, exportNameOrTypeName: string, maybeTypeName?: string): unknown;
|
|
18
29
|
//# sourceMappingURL=compact-metadata.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compact-metadata.d.ts","sourceRoot":"","sources":["../../src/reflection/compact-metadata.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compact-metadata.d.ts","sourceRoot":"","sources":["../../src/reflection/compact-metadata.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,OAAO,EAAE,EAAE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,CAAC,CAE1I;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,MAAM,EACpD,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,SAAS,OAAO,EAAE,EAC9B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GACzC,CAAC,CAMH;AAED,qEAAqE;AACrE,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,OAAO,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAmB9H;AAED,8EAA8E;AAC9E,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,OAAO,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAyB9H;AAED,8EAA8E;AAC9E,wBAAgB,6BAA6B,CACzC,UAAU,EAAE,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,EAC9D,qBAAqB,EAAE,MAAM,EAC7B,oBAAoB,EAAE,MAAM,EAC5B,aAAa,CAAC,EAAE,MAAM,GACvB,OAAO,CAqBT"}
|
|
@@ -2,7 +2,9 @@ package main
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"bytes"
|
|
5
|
+
"crypto/sha256"
|
|
5
6
|
"encoding/json"
|
|
7
|
+
"fmt"
|
|
6
8
|
"strconv"
|
|
7
9
|
"strings"
|
|
8
10
|
|
|
@@ -12,13 +14,15 @@ import (
|
|
|
12
14
|
|
|
13
15
|
const (
|
|
14
16
|
compactMetadataRuntimeSpec = "@zyno-io/ts-reflection/type-metadata-runtime"
|
|
15
|
-
compactMetadataDecoderName = "
|
|
16
|
-
compactMetadataRegistryName = "
|
|
17
|
+
compactMetadataDecoderName = "decodeCompactMetadataV2"
|
|
18
|
+
compactMetadataRegistryName = "createCompactMetadataRegistryV2"
|
|
17
19
|
compactMetadataAliasResolverName = "resolveCompactMetadataAliasV1"
|
|
18
20
|
compactMetadataReferenceKey = "$tsf"
|
|
19
21
|
compactMetadataImportKey = "$tsfImport"
|
|
20
22
|
compactMetadataAliasKey = "$tsfAlias"
|
|
21
23
|
compactMetadataTypeKey = "$tsfType"
|
|
24
|
+
compactMetadataNodeKey = "$tsfNode"
|
|
25
|
+
compactMetadataGraphMinBytes = 64
|
|
22
26
|
)
|
|
23
27
|
|
|
24
28
|
type compactMetadataEncoding struct {
|
|
@@ -32,6 +36,23 @@ type compactMetadataEncoder struct {
|
|
|
32
36
|
referenceIndexes map[string]int
|
|
33
37
|
referenceKey func(*shimast.Node) (string, bool)
|
|
34
38
|
runtimeRecipe func(*compactMetadataEncoder, *shimast.Node) bool
|
|
39
|
+
graph *compactMetadataGraph
|
|
40
|
+
graphRoot *shimast.Node
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type compactMetadataGraphNode struct {
|
|
44
|
+
key string
|
|
45
|
+
size int
|
|
46
|
+
container bool
|
|
47
|
+
shareable bool
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type compactMetadataGraph struct {
|
|
51
|
+
info map[*shimast.Node]compactMetadataGraphNode
|
|
52
|
+
counts map[string]int
|
|
53
|
+
indexes map[string]int
|
|
54
|
+
nodes []*shimast.Node
|
|
55
|
+
roots map[*shimast.Node]bool
|
|
35
56
|
}
|
|
36
57
|
|
|
37
58
|
type compactMetadataRuntimeInterner struct {
|
|
@@ -129,7 +150,47 @@ func encodeCompactMetadataWithRuntimeRecipes(
|
|
|
129
150
|
}
|
|
130
151
|
}
|
|
131
152
|
|
|
153
|
+
func encodeCompactMetadataV2WithRuntimeRecipes(
|
|
154
|
+
root *shimast.Node,
|
|
155
|
+
referenceKey func(*shimast.Node) (string, bool),
|
|
156
|
+
runtimeRecipe func(*compactMetadataEncoder, *shimast.Node) bool,
|
|
157
|
+
metadataTypeResolver string,
|
|
158
|
+
preserveArrayElements bool,
|
|
159
|
+
) compactMetadataEncoding {
|
|
160
|
+
encoder := &compactMetadataEncoder{
|
|
161
|
+
referenceIndexes: map[string]int{},
|
|
162
|
+
referenceKey: referenceKey,
|
|
163
|
+
runtimeRecipe: runtimeRecipe,
|
|
164
|
+
}
|
|
165
|
+
encoder.graph = buildCompactMetadataGraph(root, referenceKey, metadataTypeResolver)
|
|
166
|
+
if preserveArrayElements && root != nil && root.Kind == shimast.KindArrayLiteralExpression {
|
|
167
|
+
for _, element := range root.AsArrayLiteralExpression().Elements.Nodes {
|
|
168
|
+
encoder.graph.roots[element] = true
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
encoder.buffer.WriteString("[2,")
|
|
172
|
+
encoder.writeValue(root)
|
|
173
|
+
encoder.buffer.WriteString(",[")
|
|
174
|
+
for index := 0; index < len(encoder.graph.nodes); index++ {
|
|
175
|
+
if index != 0 {
|
|
176
|
+
encoder.buffer.WriteByte(',')
|
|
177
|
+
}
|
|
178
|
+
node := encoder.graph.nodes[index]
|
|
179
|
+
encoder.graphRoot = node
|
|
180
|
+
encoder.writeValue(node)
|
|
181
|
+
encoder.graphRoot = nil
|
|
182
|
+
}
|
|
183
|
+
encoder.buffer.WriteString("]]")
|
|
184
|
+
return compactMetadataEncoding{
|
|
185
|
+
serialized: encoder.buffer.String(),
|
|
186
|
+
references: encoder.references,
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
132
190
|
func (encoder *compactMetadataEncoder) writeValue(node *shimast.Node) {
|
|
191
|
+
if encoder.writeGraphReference(node) {
|
|
192
|
+
return
|
|
193
|
+
}
|
|
133
194
|
start := encoder.buffer.Len()
|
|
134
195
|
referenceStart := len(encoder.references)
|
|
135
196
|
if encoder.writeJSONValue(node) {
|
|
@@ -140,6 +201,26 @@ func (encoder *compactMetadataEncoder) writeValue(node *shimast.Node) {
|
|
|
140
201
|
encoder.writeReference(node)
|
|
141
202
|
}
|
|
142
203
|
|
|
204
|
+
func (encoder *compactMetadataEncoder) writeGraphReference(node *shimast.Node) bool {
|
|
205
|
+
if encoder.graph == nil || node == nil || node == encoder.graphRoot || encoder.graph.roots[node] {
|
|
206
|
+
return false
|
|
207
|
+
}
|
|
208
|
+
info, ok := encoder.graph.info[node]
|
|
209
|
+
if !ok || !info.container || !info.shareable || info.size < compactMetadataGraphMinBytes || encoder.graph.counts[info.key] < 2 {
|
|
210
|
+
return false
|
|
211
|
+
}
|
|
212
|
+
index, ok := encoder.graph.indexes[info.key]
|
|
213
|
+
if !ok {
|
|
214
|
+
index = len(encoder.graph.nodes)
|
|
215
|
+
encoder.graph.indexes[info.key] = index
|
|
216
|
+
encoder.graph.nodes = append(encoder.graph.nodes, node)
|
|
217
|
+
}
|
|
218
|
+
encoder.buffer.WriteString(`{"` + compactMetadataNodeKey + `":`)
|
|
219
|
+
encoder.buffer.WriteString(strconv.Itoa(index))
|
|
220
|
+
encoder.buffer.WriteByte('}')
|
|
221
|
+
return true
|
|
222
|
+
}
|
|
223
|
+
|
|
143
224
|
func (encoder *compactMetadataEncoder) writeJSONValue(node *shimast.Node) bool {
|
|
144
225
|
if node == nil {
|
|
145
226
|
return false
|
|
@@ -215,7 +296,8 @@ func (encoder *compactMetadataEncoder) writeObject(object *shimast.ObjectLiteral
|
|
|
215
296
|
}
|
|
216
297
|
|
|
217
298
|
func isCompactMetadataReservedKey(name string) bool {
|
|
218
|
-
return name == compactMetadataReferenceKey || name == compactMetadataImportKey || name == compactMetadataAliasKey ||
|
|
299
|
+
return name == compactMetadataReferenceKey || name == compactMetadataImportKey || name == compactMetadataAliasKey ||
|
|
300
|
+
name == compactMetadataTypeKey || name == compactMetadataNodeKey
|
|
219
301
|
}
|
|
220
302
|
|
|
221
303
|
func compactMetadataPropertyName(property *shimast.Node) (string, bool) {
|
|
@@ -302,6 +384,164 @@ func (encoder *compactMetadataEncoder) writeReferenceMarker(index int) {
|
|
|
302
384
|
encoder.buffer.WriteByte('}')
|
|
303
385
|
}
|
|
304
386
|
|
|
387
|
+
func buildCompactMetadataGraph(
|
|
388
|
+
root *shimast.Node,
|
|
389
|
+
referenceKey func(*shimast.Node) (string, bool),
|
|
390
|
+
metadataTypeResolver string,
|
|
391
|
+
) *compactMetadataGraph {
|
|
392
|
+
graph := &compactMetadataGraph{
|
|
393
|
+
info: map[*shimast.Node]compactMetadataGraphNode{},
|
|
394
|
+
counts: map[string]int{},
|
|
395
|
+
indexes: map[string]int{},
|
|
396
|
+
roots: map[*shimast.Node]bool{},
|
|
397
|
+
}
|
|
398
|
+
var fingerprint func(*shimast.Node) compactMetadataGraphNode
|
|
399
|
+
fingerprint = func(node *shimast.Node) compactMetadataGraphNode {
|
|
400
|
+
if node == nil {
|
|
401
|
+
return compactMetadataGraphNode{}
|
|
402
|
+
}
|
|
403
|
+
if cached, ok := graph.info[node]; ok {
|
|
404
|
+
return cached
|
|
405
|
+
}
|
|
406
|
+
if node.Kind == shimast.KindParenthesizedExpression {
|
|
407
|
+
result := fingerprint(node.AsParenthesizedExpression().Expression)
|
|
408
|
+
graph.info[node] = result
|
|
409
|
+
return result
|
|
410
|
+
}
|
|
411
|
+
result := compactMetadataGraphNode{}
|
|
412
|
+
var signature strings.Builder
|
|
413
|
+
switch node.Kind {
|
|
414
|
+
case shimast.KindObjectLiteralExpression:
|
|
415
|
+
object := node.AsObjectLiteralExpression()
|
|
416
|
+
if object == nil || object.Properties == nil {
|
|
417
|
+
result = compactMetadataGraphNode{key: compactMetadataFingerprint("o"), size: 2, container: true, shareable: true}
|
|
418
|
+
break
|
|
419
|
+
}
|
|
420
|
+
if len(object.Properties.Nodes) == 1 {
|
|
421
|
+
if name, ok := compactMetadataPropertyName(object.Properties.Nodes[0]); ok && isCompactMetadataReservedKey(name) {
|
|
422
|
+
break
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
signature.WriteString("object:")
|
|
426
|
+
size := 2
|
|
427
|
+
shareable := true
|
|
428
|
+
for _, property := range object.Properties.Nodes {
|
|
429
|
+
name, ok := compactMetadataPropertyName(property)
|
|
430
|
+
assignment := property.AsPropertyAssignment()
|
|
431
|
+
if !ok || name == "__proto__" || assignment == nil {
|
|
432
|
+
shareable = false
|
|
433
|
+
break
|
|
434
|
+
}
|
|
435
|
+
child := fingerprint(assignment.Initializer)
|
|
436
|
+
if !child.shareable {
|
|
437
|
+
shareable = false
|
|
438
|
+
break
|
|
439
|
+
}
|
|
440
|
+
signature.WriteString(strconv.Quote(name))
|
|
441
|
+
signature.WriteByte(':')
|
|
442
|
+
signature.WriteString(child.key)
|
|
443
|
+
signature.WriteByte(';')
|
|
444
|
+
size += len(strconv.Quote(name)) + 1 + child.size + 1
|
|
445
|
+
}
|
|
446
|
+
if shareable {
|
|
447
|
+
result = compactMetadataGraphNode{key: compactMetadataFingerprint(signature.String()), size: size, container: true, shareable: true}
|
|
448
|
+
}
|
|
449
|
+
case shimast.KindArrayLiteralExpression:
|
|
450
|
+
array := node.AsArrayLiteralExpression()
|
|
451
|
+
signature.WriteString("array:")
|
|
452
|
+
size := 2
|
|
453
|
+
shareable := array != nil
|
|
454
|
+
if shareable && array.Elements != nil {
|
|
455
|
+
for _, element := range array.Elements.Nodes {
|
|
456
|
+
if element == nil || element.Kind == shimast.KindOmittedExpression || element.Kind == shimast.KindSpreadElement {
|
|
457
|
+
shareable = false
|
|
458
|
+
break
|
|
459
|
+
}
|
|
460
|
+
child := fingerprint(element)
|
|
461
|
+
if !child.shareable {
|
|
462
|
+
shareable = false
|
|
463
|
+
break
|
|
464
|
+
}
|
|
465
|
+
signature.WriteString(child.key)
|
|
466
|
+
signature.WriteByte(';')
|
|
467
|
+
size += child.size + 1
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if shareable {
|
|
471
|
+
result = compactMetadataGraphNode{key: compactMetadataFingerprint(signature.String()), size: size, container: true, shareable: true}
|
|
472
|
+
}
|
|
473
|
+
case shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral:
|
|
474
|
+
value, _ := json.Marshal(node.Text())
|
|
475
|
+
result = compactMetadataGraphNode{key: compactMetadataFingerprint("string:" + string(value)), size: len(value), shareable: true}
|
|
476
|
+
case shimast.KindNumericLiteral:
|
|
477
|
+
if json.Valid([]byte(node.Text())) {
|
|
478
|
+
result = compactMetadataGraphNode{key: compactMetadataFingerprint("number:" + node.Text()), size: len(node.Text()), shareable: true}
|
|
479
|
+
}
|
|
480
|
+
case shimast.KindTrueKeyword:
|
|
481
|
+
result = compactMetadataGraphNode{key: compactMetadataFingerprint("true"), size: 4, shareable: true}
|
|
482
|
+
case shimast.KindFalseKeyword:
|
|
483
|
+
result = compactMetadataGraphNode{key: compactMetadataFingerprint("false"), size: 5, shareable: true}
|
|
484
|
+
case shimast.KindNullKeyword:
|
|
485
|
+
result = compactMetadataGraphNode{key: compactMetadataFingerprint("null"), size: 4, shareable: true}
|
|
486
|
+
case shimast.KindPrefixUnaryExpression:
|
|
487
|
+
unary := node.AsPrefixUnaryExpression()
|
|
488
|
+
if unary != nil && unary.Operator == shimast.KindMinusToken && unary.Operand != nil && unary.Operand.Kind == shimast.KindNumericLiteral {
|
|
489
|
+
value := "-" + unary.Operand.Text()
|
|
490
|
+
if json.Valid([]byte(value)) {
|
|
491
|
+
result = compactMetadataGraphNode{key: compactMetadataFingerprint("number:" + value), size: len(value), shareable: true}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
default:
|
|
495
|
+
if index, ok := compactMetadataTypeRecipe(node, metadataTypeResolver); ok {
|
|
496
|
+
value := fmt.Sprintf("type:%d", index)
|
|
497
|
+
result = compactMetadataGraphNode{key: compactMetadataFingerprint(value), size: len(value) + 8, shareable: true}
|
|
498
|
+
} else if referenceKey != nil {
|
|
499
|
+
if key, ok := referenceKey(node); ok {
|
|
500
|
+
result = compactMetadataGraphNode{key: compactMetadataFingerprint("reference:" + key), size: len(key) + 8, shareable: true}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
graph.info[node] = result
|
|
505
|
+
if result.container && result.shareable && result.size >= compactMetadataGraphMinBytes {
|
|
506
|
+
graph.counts[result.key]++
|
|
507
|
+
}
|
|
508
|
+
return result
|
|
509
|
+
}
|
|
510
|
+
fingerprint(root)
|
|
511
|
+
return graph
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
func compactMetadataFingerprint(value string) string {
|
|
515
|
+
hash := sha256.Sum256([]byte(value))
|
|
516
|
+
return string(hash[:])
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
func compactMetadataEncodingForSizeGuard(
|
|
520
|
+
metadata *shimast.Node,
|
|
521
|
+
imports *astImportRegistry,
|
|
522
|
+
runtimeReferences *compactMetadataRuntimeInterner,
|
|
523
|
+
metadataTypeResolver string,
|
|
524
|
+
preserveArrayElements bool,
|
|
525
|
+
inlinePureJSON bool,
|
|
526
|
+
) compactMetadataEncoding {
|
|
527
|
+
runtimeRecipe := func(encoder *compactMetadataEncoder, expression *shimast.Node) bool {
|
|
528
|
+
return writeCompactMetadataRuntimeRecipe(encoder, expression, imports, metadataTypeResolver)
|
|
529
|
+
}
|
|
530
|
+
if inlinePureJSON {
|
|
531
|
+
encoding := encodeCompactMetadataWithRuntimeRecipes(metadata, runtimeReferences.deduplicationKey, runtimeRecipe)
|
|
532
|
+
if len(encoding.references) == 0 && !strings.Contains(encoding.serialized, `"$tsf`) {
|
|
533
|
+
return encoding
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return encodeCompactMetadataV2WithRuntimeRecipes(
|
|
537
|
+
metadata,
|
|
538
|
+
runtimeReferences.deduplicationKey,
|
|
539
|
+
runtimeRecipe,
|
|
540
|
+
metadataTypeResolver,
|
|
541
|
+
preserveArrayElements,
|
|
542
|
+
)
|
|
543
|
+
}
|
|
544
|
+
|
|
305
545
|
func materializeCompactMetadataExpression(
|
|
306
546
|
ec *shimprinter.EmitContext,
|
|
307
547
|
imports *astImportRegistry,
|
|
@@ -322,9 +562,10 @@ func materializeCompactAliasMetadataExpression(
|
|
|
322
562
|
runtimeReferences *compactMetadataRuntimeInterner,
|
|
323
563
|
template expressionTemplate,
|
|
324
564
|
metadataTypeResolver string,
|
|
565
|
+
inlinePureJSON bool,
|
|
325
566
|
) *shimast.Node {
|
|
326
567
|
metadata := template.materialize(ec, imports)
|
|
327
|
-
return materializeCompactMetadataNode(ec, imports, runtimeReferences, metadata, metadataTypeResolver, false,
|
|
568
|
+
return materializeCompactMetadataNode(ec, imports, runtimeReferences, metadata, metadataTypeResolver, false, inlinePureJSON)
|
|
328
569
|
}
|
|
329
570
|
|
|
330
571
|
func materializeCompactMetadataRegistry(
|
|
@@ -351,12 +592,46 @@ func materializeCompactMetadataNode(
|
|
|
351
592
|
registry bool,
|
|
352
593
|
inlinePureJSON bool,
|
|
353
594
|
) *shimast.Node {
|
|
354
|
-
|
|
595
|
+
encodeV1 := func() compactMetadataEncoding {
|
|
596
|
+
return encodeCompactMetadataWithRuntimeRecipes(
|
|
597
|
+
metadata,
|
|
598
|
+
runtimeReferences.deduplicationKey,
|
|
599
|
+
func(encoder *compactMetadataEncoder, expression *shimast.Node) bool {
|
|
600
|
+
return writeCompactMetadataRuntimeRecipe(encoder, expression, imports, metadataTypeResolver)
|
|
601
|
+
},
|
|
602
|
+
)
|
|
603
|
+
}
|
|
604
|
+
if inlinePureJSON {
|
|
605
|
+
encoding := encodeV1()
|
|
606
|
+
if len(encoding.references) == 0 && !strings.Contains(encoding.serialized, `"$tsf`) {
|
|
607
|
+
parsed := ec.Factory.NewCallExpression(
|
|
608
|
+
ec.Factory.NewPropertyAccessExpression(
|
|
609
|
+
ec.Factory.NewIdentifier("JSON"),
|
|
610
|
+
nil,
|
|
611
|
+
ec.Factory.NewIdentifier("parse"),
|
|
612
|
+
shimast.NodeFlagsNone,
|
|
613
|
+
),
|
|
614
|
+
nil,
|
|
615
|
+
nil,
|
|
616
|
+
ec.Factory.NewNodeList([]*shimast.Node{ec.Factory.NewStringLiteral(encoding.serialized, shimast.TokenFlagsNone)}),
|
|
617
|
+
shimast.NodeFlagsNone,
|
|
618
|
+
)
|
|
619
|
+
return ec.Factory.NewElementAccessExpression(
|
|
620
|
+
parsed,
|
|
621
|
+
nil,
|
|
622
|
+
ec.Factory.NewNumericLiteral("1", shimast.TokenFlagsNone),
|
|
623
|
+
shimast.NodeFlagsNone,
|
|
624
|
+
)
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
encoding := encodeCompactMetadataV2WithRuntimeRecipes(
|
|
355
628
|
metadata,
|
|
356
629
|
runtimeReferences.deduplicationKey,
|
|
357
630
|
func(encoder *compactMetadataEncoder, expression *shimast.Node) bool {
|
|
358
631
|
return writeCompactMetadataRuntimeRecipe(encoder, expression, imports, metadataTypeResolver)
|
|
359
632
|
},
|
|
633
|
+
metadataTypeResolver,
|
|
634
|
+
registry,
|
|
360
635
|
)
|
|
361
636
|
references := make([]*shimast.Node, 0, len(encoding.references))
|
|
362
637
|
for _, reference := range encoding.references {
|
|
@@ -366,26 +641,6 @@ func materializeCompactMetadataNode(
|
|
|
366
641
|
// its original binding.
|
|
367
642
|
references = append(references, ec.Factory.DeepCloneNode(reference))
|
|
368
643
|
}
|
|
369
|
-
if inlinePureJSON && len(references) == 0 && !strings.Contains(encoding.serialized, `"$tsf`) {
|
|
370
|
-
parsed := ec.Factory.NewCallExpression(
|
|
371
|
-
ec.Factory.NewPropertyAccessExpression(
|
|
372
|
-
ec.Factory.NewIdentifier("JSON"),
|
|
373
|
-
nil,
|
|
374
|
-
ec.Factory.NewIdentifier("parse"),
|
|
375
|
-
shimast.NodeFlagsNone,
|
|
376
|
-
),
|
|
377
|
-
nil,
|
|
378
|
-
nil,
|
|
379
|
-
ec.Factory.NewNodeList([]*shimast.Node{ec.Factory.NewStringLiteral(encoding.serialized, shimast.TokenFlagsNone)}),
|
|
380
|
-
shimast.NodeFlagsNone,
|
|
381
|
-
)
|
|
382
|
-
return ec.Factory.NewElementAccessExpression(
|
|
383
|
-
parsed,
|
|
384
|
-
nil,
|
|
385
|
-
ec.Factory.NewNumericLiteral("1", shimast.TokenFlagsNone),
|
|
386
|
-
shimast.NodeFlagsNone,
|
|
387
|
-
)
|
|
388
|
-
}
|
|
389
644
|
helperName := compactMetadataDecoderName
|
|
390
645
|
if registry {
|
|
391
646
|
helperName = compactMetadataRegistryName
|
|
@@ -6,18 +6,22 @@ import (
|
|
|
6
6
|
"strings"
|
|
7
7
|
|
|
8
8
|
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
9
|
+
shimprinter "github.com/microsoft/typescript-go/shim/printer"
|
|
9
10
|
"github.com/samchon/ttsc/packages/ttsc/driver"
|
|
10
11
|
)
|
|
11
12
|
|
|
13
|
+
const maxCompactMetadataPayloadBytes = 1024 * 1024
|
|
14
|
+
|
|
12
15
|
type emissionPlans map[string]*fileEmissionPlan
|
|
13
16
|
|
|
14
17
|
type fileEmissionPlan struct {
|
|
15
|
-
calls
|
|
16
|
-
classes
|
|
17
|
-
aliases
|
|
18
|
-
metadataTypes
|
|
19
|
-
metadataTypeResolver
|
|
20
|
-
|
|
18
|
+
calls map[int]callEmissionPlan
|
|
19
|
+
classes map[int]classEmissionPlan
|
|
20
|
+
aliases *expressionTemplate
|
|
21
|
+
metadataTypes []expressionTemplate
|
|
22
|
+
metadataTypeResolver string
|
|
23
|
+
decodePureJSONAliases bool
|
|
24
|
+
commonJS bool
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
type callEmissionPlan struct {
|
|
@@ -95,8 +99,9 @@ func buildEmissionPlans(reg *registry, program *driver.Program, emitTypeAliases
|
|
|
95
99
|
continue
|
|
96
100
|
}
|
|
97
101
|
plan := &fileEmissionPlan{
|
|
98
|
-
calls:
|
|
99
|
-
classes:
|
|
102
|
+
calls: map[int]callEmissionPlan{},
|
|
103
|
+
classes: map[int]classEmissionPlan{},
|
|
104
|
+
decodePureJSONAliases: emitMetadataRuntimeImport,
|
|
100
105
|
}
|
|
101
106
|
metadataTypes := newMetadataTypeInterner(info.file.Text())
|
|
102
107
|
if program != nil && program.TSProgram != nil {
|
|
@@ -145,6 +150,9 @@ func buildEmissionPlans(reg *registry, program *driver.Program, emitTypeAliases
|
|
|
145
150
|
plan.aliases = &template
|
|
146
151
|
}
|
|
147
152
|
}
|
|
153
|
+
if err := validateCompactMetadataSizes(info, plan); err != nil {
|
|
154
|
+
return nil, err
|
|
155
|
+
}
|
|
148
156
|
if !emitMetadataRuntimeImport {
|
|
149
157
|
if requirement := metadataRuntimeRequirement(plan); requirement != "" {
|
|
150
158
|
return nil, fmt.Errorf(
|
|
@@ -162,6 +170,88 @@ func buildEmissionPlans(reg *registry, program *driver.Program, emitTypeAliases
|
|
|
162
170
|
return plans, nil
|
|
163
171
|
}
|
|
164
172
|
|
|
173
|
+
func validateCompactMetadataSizes(info *fileInfo, plan *fileEmissionPlan) error {
|
|
174
|
+
if info == nil || info.file == nil || plan == nil {
|
|
175
|
+
return nil
|
|
176
|
+
}
|
|
177
|
+
ec := shimprinter.NewEmitContext()
|
|
178
|
+
imports := newAstImportRegistry(ec, info.file, plan.commonJS)
|
|
179
|
+
runtimeReferences := newCompactMetadataRuntimeInterner(ec, info.file)
|
|
180
|
+
validate := func(surface string, template expressionTemplate, preserveArrayElements bool, inlinePureJSON bool) error {
|
|
181
|
+
metadata := template.materialize(ec, imports)
|
|
182
|
+
encoding := compactMetadataEncodingForSizeGuard(
|
|
183
|
+
metadata,
|
|
184
|
+
imports,
|
|
185
|
+
runtimeReferences,
|
|
186
|
+
plan.metadataTypeResolver,
|
|
187
|
+
preserveArrayElements,
|
|
188
|
+
inlinePureJSON,
|
|
189
|
+
)
|
|
190
|
+
if len(encoding.serialized) > maxCompactMetadataPayloadBytes {
|
|
191
|
+
return fmt.Errorf(
|
|
192
|
+
"%s: compact metadata for %s is %d bytes after graph interning; limit is %d bytes",
|
|
193
|
+
info.file.FileName(),
|
|
194
|
+
surface,
|
|
195
|
+
len(encoding.serialized),
|
|
196
|
+
maxCompactMetadataPayloadBytes,
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
return nil
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
classPositions := make([]int, 0, len(plan.classes))
|
|
203
|
+
for position := range plan.classes {
|
|
204
|
+
classPositions = append(classPositions, position)
|
|
205
|
+
}
|
|
206
|
+
sort.Ints(classPositions)
|
|
207
|
+
for _, position := range classPositions {
|
|
208
|
+
class := plan.classes[position]
|
|
209
|
+
if err := validate("class "+class.name, class.metadata, false, false); err != nil {
|
|
210
|
+
return err
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
callPositions := make([]int, 0, len(plan.calls))
|
|
214
|
+
for position := range plan.calls {
|
|
215
|
+
callPositions = append(callPositions, position)
|
|
216
|
+
}
|
|
217
|
+
sort.Ints(callPositions)
|
|
218
|
+
for _, position := range callPositions {
|
|
219
|
+
call := plan.calls[position]
|
|
220
|
+
if err := validate("call "+call.name, call.metadata, false, false); err != nil {
|
|
221
|
+
return err
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if plan.aliases != nil {
|
|
225
|
+
if err := validate("exported aliases", *plan.aliases, false, !plan.decodePureJSONAliases); err != nil {
|
|
226
|
+
return err
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if len(plan.metadataTypes) != 0 {
|
|
230
|
+
elements := make([]*shimast.Node, 0, len(plan.metadataTypes))
|
|
231
|
+
for _, template := range plan.metadataTypes {
|
|
232
|
+
elements = append(elements, template.materialize(ec, imports))
|
|
233
|
+
}
|
|
234
|
+
metadata := ec.Factory.NewArrayLiteralExpression(ec.Factory.NewNodeList(elements), false)
|
|
235
|
+
encoding := compactMetadataEncodingForSizeGuard(
|
|
236
|
+
metadata,
|
|
237
|
+
imports,
|
|
238
|
+
runtimeReferences,
|
|
239
|
+
plan.metadataTypeResolver,
|
|
240
|
+
true,
|
|
241
|
+
false,
|
|
242
|
+
)
|
|
243
|
+
if len(encoding.serialized) > maxCompactMetadataPayloadBytes {
|
|
244
|
+
return fmt.Errorf(
|
|
245
|
+
"%s: compact metadata for shared type registry is %d bytes after graph interning; limit is %d bytes",
|
|
246
|
+
info.file.FileName(),
|
|
247
|
+
len(encoding.serialized),
|
|
248
|
+
maxCompactMetadataPayloadBytes,
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return nil
|
|
253
|
+
}
|
|
254
|
+
|
|
165
255
|
// metadataRuntimeRequirement reports the first generated construct that cannot
|
|
166
256
|
// be emitted without TSF's compact metadata runtime. Alias registries made only
|
|
167
257
|
// of JSON stay self-contained; all other current metadata surfaces use runtime
|
|
@@ -170,7 +260,7 @@ func metadataRuntimeRequirement(plan *fileEmissionPlan) string {
|
|
|
170
260
|
if plan == nil {
|
|
171
261
|
return ""
|
|
172
262
|
}
|
|
173
|
-
if plan.aliases != nil && !compactMetadataIsPureJSON(plan.aliases.parsed) {
|
|
263
|
+
if plan.aliases != nil && (plan.decodePureJSONAliases || !compactMetadataIsPureJSON(plan.aliases.parsed)) {
|
|
174
264
|
if names := runtimeAliasMetadataNames(plan.aliases.parsed); len(names) != 0 {
|
|
175
265
|
return "reflected alias metadata for " + strings.Join(names, ", ")
|
|
176
266
|
}
|
|
@@ -236,6 +326,10 @@ func aliasMetadataExpression(info *fileInfo, reg *registry) string {
|
|
|
236
326
|
}
|
|
237
327
|
continue
|
|
238
328
|
}
|
|
329
|
+
if ref, ok := reexportedTypeMetadataReference(info, reg, name); ok {
|
|
330
|
+
entries = append(entries, quote(name)+": "+externalImportedTypeExpr(ref, name))
|
|
331
|
+
continue
|
|
332
|
+
}
|
|
239
333
|
if alias, owner, _, ok := resolveExportedAlias(info, reg, name, map[string]bool{}); ok {
|
|
240
334
|
if len(alias.params) == 0 {
|
|
241
335
|
if expr := cachedAliasTypeExpr(owner, reg, alias); expr != "" && !metadataExprTooLarge(expr) {
|
|
@@ -256,6 +350,56 @@ func aliasMetadataExpression(info *fileInfo, reg *registry) string {
|
|
|
256
350
|
return "{" + strings.Join(entries, ", ") + "}"
|
|
257
351
|
}
|
|
258
352
|
|
|
353
|
+
// Re-exporting a type must not copy the owner's complete structural metadata
|
|
354
|
+
// into every barrel. Point at the immediate owning module when this compilation
|
|
355
|
+
// emits that module's alias table; it may itself contain another recipe when the
|
|
356
|
+
// export crosses more than one barrel. Declaration-only dependencies do not
|
|
357
|
+
// necessarily publish runtime alias metadata, so keep their structural metadata
|
|
358
|
+
// at the first emitted boundary instead of producing an unresolvable recipe.
|
|
359
|
+
func reexportedTypeMetadataReference(info *fileInfo, reg *registry, name string) (importRef, bool) {
|
|
360
|
+
if info == nil || reg == nil {
|
|
361
|
+
return importRef{}, false
|
|
362
|
+
}
|
|
363
|
+
if ref, ok := info.reexports[name]; ok {
|
|
364
|
+
if target := reg.byPath[ref.source]; canPublishTypeMetadata(target) && exportedTypeMetadataExists(target, reg, ref.exportName) {
|
|
365
|
+
ref.spec = emittedMetadataOwnerSpecifier(info, target, ref.spec)
|
|
366
|
+
return ref, ref.spec != "" && ref.exportName != ""
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
for _, ref := range info.exportStar {
|
|
370
|
+
target := reg.byPath[ref.source]
|
|
371
|
+
if !canPublishTypeMetadata(target) || !exportedTypeMetadataExists(target, reg, name) {
|
|
372
|
+
continue
|
|
373
|
+
}
|
|
374
|
+
ref.exportName = name
|
|
375
|
+
ref.spec = emittedMetadataOwnerSpecifier(info, target, ref.spec)
|
|
376
|
+
return ref, ref.spec != ""
|
|
377
|
+
}
|
|
378
|
+
return importRef{}, false
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
func canPublishTypeMetadata(info *fileInfo) bool {
|
|
382
|
+
return info != nil && info.file != nil && !info.file.IsDeclarationFile
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
func emittedMetadataOwnerSpecifier(info *fileInfo, target *fileInfo, spec string) string {
|
|
386
|
+
if info == nil || info.file == nil || target == nil || target.file == nil || !strings.HasPrefix(spec, ".") {
|
|
387
|
+
return spec
|
|
388
|
+
}
|
|
389
|
+
// Use an explicit runtime file rather than syntactically appending `.js` to
|
|
390
|
+
// the source specifier. The latter turns `./directory` into a nonexistent
|
|
391
|
+
// `./directory.js` instead of the emitted `./directory/index.js`.
|
|
392
|
+
return moduleSpecifierForOutput(info.file.FileName(), target.file.FileName(), true)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
func exportedTypeMetadataExists(info *fileInfo, reg *registry, name string) bool {
|
|
396
|
+
if _, _, _, ok := resolveExportedAlias(info, reg, name, map[string]bool{}); ok {
|
|
397
|
+
return true
|
|
398
|
+
}
|
|
399
|
+
_, _, _, ok := resolveExportedInterfaceDecl(info, reg, name, map[string]bool{})
|
|
400
|
+
return ok
|
|
401
|
+
}
|
|
402
|
+
|
|
259
403
|
func cachedAliasTypeExpr(info *fileInfo, reg *registry, alias aliasInfo) string {
|
|
260
404
|
if alias.metadataTooLarge {
|
|
261
405
|
return ""
|
|
@@ -233,6 +233,10 @@ func TestMetadataRuntimeRequirementAllowsPureJSONAliases(t *testing.T) {
|
|
|
233
233
|
if got := metadataRuntimeRequirement(plan); got != "" {
|
|
234
234
|
t.Fatalf("pure JSON aliases require metadata runtime: %s", got)
|
|
235
235
|
}
|
|
236
|
+
plan.decodePureJSONAliases = true
|
|
237
|
+
if got := metadataRuntimeRequirement(plan); got != "reflected alias metadata" {
|
|
238
|
+
t.Fatalf("lazy pure JSON alias requirement = %q", got)
|
|
239
|
+
}
|
|
236
240
|
}
|
|
237
241
|
|
|
238
242
|
func TestMetadataRuntimeRequirementRejectsRuntimeAliasValues(t *testing.T) {
|
|
@@ -348,6 +352,7 @@ func TestCompactMetadataEncoderEscapesReferenceMarkerCollision(t *testing.T) {
|
|
|
348
352
|
`{"$tsfImport": [0, "Model"]}`,
|
|
349
353
|
`{"$tsfAlias": [0, "Alias", "Alias"]}`,
|
|
350
354
|
`{"$tsfType": 0}`,
|
|
355
|
+
`{"$tsfNode": 0}`,
|
|
351
356
|
} {
|
|
352
357
|
template, err := parseExpressionTemplate(source)
|
|
353
358
|
if err != nil {
|
|
@@ -417,6 +422,113 @@ func TestCompactMetadataEncoderDeduplicatesGeneratedRuntimeThunks(t *testing.T)
|
|
|
417
422
|
}
|
|
418
423
|
}
|
|
419
424
|
|
|
425
|
+
func TestCompactMetadataV2InternsRepeatedGraphsWithRuntimeReferences(t *testing.T) {
|
|
426
|
+
file := parseTestSourceFile(t, "/project/model.ts", `class Model {}`)
|
|
427
|
+
template, err := parseExpressionTemplate(`{
|
|
428
|
+
first: {kind: 16, classType: () => Model, properties: [{name: "value", type: {kind: 6}}]},
|
|
429
|
+
second: {kind: 16, classType: () => Model, properties: [{name: "value", type: {kind: 6}}]}
|
|
430
|
+
}`)
|
|
431
|
+
if err != nil {
|
|
432
|
+
t.Fatal(err)
|
|
433
|
+
}
|
|
434
|
+
ec := shimprinter.NewEmitContext()
|
|
435
|
+
interner := newCompactMetadataRuntimeInterner(ec, file)
|
|
436
|
+
encoding := encodeCompactMetadataV2WithRuntimeRecipes(template.parsed, interner.deduplicationKey, nil, "", false)
|
|
437
|
+
if !strings.HasPrefix(encoding.serialized, `[2,`) {
|
|
438
|
+
t.Fatalf("V2 compact payload = %s", encoding.serialized)
|
|
439
|
+
}
|
|
440
|
+
if strings.Count(encoding.serialized, `{"$tsfNode":0}`) != 2 {
|
|
441
|
+
t.Fatalf("repeated graph was not interned: %s", encoding.serialized)
|
|
442
|
+
}
|
|
443
|
+
if len(encoding.references) != 1 {
|
|
444
|
+
t.Fatalf("runtime references = %d, want 1", len(encoding.references))
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
func TestAliasMetadataUsesOwnerRecipesForReexports(t *testing.T) {
|
|
449
|
+
originFile := parseTestSourceFile(t, "/project/origin/index.ts", `export type Shared = { value: string }`)
|
|
450
|
+
barrelFile := parseTestSourceFile(t, "/project/barrel.ts", `export * from "./origin"`)
|
|
451
|
+
origin := &fileInfo{
|
|
452
|
+
file: originFile,
|
|
453
|
+
moduleKey: moduleKey(originFile.FileName()),
|
|
454
|
+
aliases: map[string]aliasInfo{"Shared": {body: `{ value: string }`, exported: true}},
|
|
455
|
+
interfaces: map[string][]interfaceInfo{},
|
|
456
|
+
reexports: map[string]importRef{},
|
|
457
|
+
}
|
|
458
|
+
barrel := &fileInfo{
|
|
459
|
+
file: barrelFile,
|
|
460
|
+
moduleKey: moduleKey(barrelFile.FileName()),
|
|
461
|
+
aliases: map[string]aliasInfo{},
|
|
462
|
+
interfaces: map[string][]interfaceInfo{},
|
|
463
|
+
reexports: map[string]importRef{},
|
|
464
|
+
exportStar: []importRef{{source: origin.moduleKey, spec: "./origin"}},
|
|
465
|
+
}
|
|
466
|
+
reg := ®istry{byPath: map[string]*fileInfo{origin.moduleKey: origin, barrel.moduleKey: barrel}}
|
|
467
|
+
|
|
468
|
+
got := aliasMetadataExpression(barrel, reg)
|
|
469
|
+
assertContainsAll(t, got, `"Shared": __tsf_runtime_alias__("./origin/index.js", "Shared", "Shared")`)
|
|
470
|
+
assertNotContains(t, got, `name: "value"`)
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
func TestAliasMetadataExpandsDeclarationOnlyReexportBoundary(t *testing.T) {
|
|
474
|
+
originFile := parseTestSourceFile(t, "/dependencies/origin.d.ts", `export type Shared = { value: string }`)
|
|
475
|
+
barrelFile := parseTestSourceFile(t, "/project/barrel.ts", `export * from "external-package"`)
|
|
476
|
+
origin := &fileInfo{
|
|
477
|
+
file: originFile,
|
|
478
|
+
moduleKey: moduleKey(originFile.FileName()),
|
|
479
|
+
aliases: map[string]aliasInfo{"Shared": {body: `{ value: string }`, exported: true}},
|
|
480
|
+
interfaces: map[string][]interfaceInfo{},
|
|
481
|
+
reexports: map[string]importRef{},
|
|
482
|
+
}
|
|
483
|
+
barrel := &fileInfo{
|
|
484
|
+
file: barrelFile,
|
|
485
|
+
moduleKey: moduleKey(barrelFile.FileName()),
|
|
486
|
+
aliases: map[string]aliasInfo{},
|
|
487
|
+
interfaces: map[string][]interfaceInfo{},
|
|
488
|
+
reexports: map[string]importRef{},
|
|
489
|
+
exportStar: []importRef{{source: origin.moduleKey, spec: "external-package"}},
|
|
490
|
+
}
|
|
491
|
+
reg := ®istry{byPath: map[string]*fileInfo{origin.moduleKey: origin, barrel.moduleKey: barrel}}
|
|
492
|
+
|
|
493
|
+
got := aliasMetadataExpression(barrel, reg)
|
|
494
|
+
assertContainsAll(t, got, `"Shared":`, `name: "value"`)
|
|
495
|
+
assertNotContains(t, got, `__tsf_runtime_alias__`)
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
func TestCompactMetadataSizeGuardRejectsOversizedPayload(t *testing.T) {
|
|
499
|
+
file := parseTestSourceFile(t, "/project/oversized.ts", `class Oversized {}`)
|
|
500
|
+
template, err := parseExpressionTemplate(`{kind: 2, typeName: "` + strings.Repeat("x", maxCompactMetadataPayloadBytes) + `"}`)
|
|
501
|
+
if err != nil {
|
|
502
|
+
t.Fatal(err)
|
|
503
|
+
}
|
|
504
|
+
plan := &fileEmissionPlan{
|
|
505
|
+
calls: map[int]callEmissionPlan{},
|
|
506
|
+
classes: map[int]classEmissionPlan{1: {name: "Oversized", metadata: template}},
|
|
507
|
+
commonJS: true,
|
|
508
|
+
}
|
|
509
|
+
err = validateCompactMetadataSizes(&fileInfo{file: file}, plan)
|
|
510
|
+
if err == nil || !strings.Contains(err.Error(), "limit is 1048576 bytes") {
|
|
511
|
+
t.Fatalf("size guard error = %v", err)
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
func TestCompactMetadataSizeGuardMeasuresAfterGraphInterning(t *testing.T) {
|
|
516
|
+
file := parseTestSourceFile(t, "/project/compacted.ts", `class Compacted {}`)
|
|
517
|
+
repeated := strings.Repeat("x", maxCompactMetadataPayloadBytes/2+1024)
|
|
518
|
+
template, err := parseExpressionTemplate(`{first: {value: "` + repeated + `"}, second: {value: "` + repeated + `"}}`)
|
|
519
|
+
if err != nil {
|
|
520
|
+
t.Fatal(err)
|
|
521
|
+
}
|
|
522
|
+
plan := &fileEmissionPlan{
|
|
523
|
+
calls: map[int]callEmissionPlan{},
|
|
524
|
+
classes: map[int]classEmissionPlan{1: {name: "Compacted", metadata: template}},
|
|
525
|
+
commonJS: true,
|
|
526
|
+
}
|
|
527
|
+
if err := validateCompactMetadataSizes(&fileInfo{file: file}, plan); err != nil {
|
|
528
|
+
t.Fatalf("compacted metadata failed size guard: %v", err)
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
420
532
|
func TestMetadataTypeInternerKeepsRuntimeExpressionsAtUseSite(t *testing.T) {
|
|
421
533
|
interner := newMetadataTypeInterner("")
|
|
422
534
|
runtime := `{kind: 16, classType: () => LocalModel}`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=1,t=`$tsf`,n=`$tsfImport`,r=`$tsfAlias`,i=`$tsfType`;function
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=1,t=`$tsf`,n=`$tsfImport`,r=`$tsfAlias`,i=`$tsfType`,a=`$tsfNode`;function o(e,t,n){return p(d(e),t,n)}function s(e,t,n){return h(()=>{let[r,i]=f(e);return p(r,t,n,m(i,t,n))})}function c(e,t){let n=d(e);if(!Array.isArray(n))throw Error(`Invalid TSF compact metadata registry`);let r=Array.from({length:n.length}),i=new Uint8Array(n.length),a=e=>{if(!Number.isSafeInteger(e)||e<0||e>=n.length)throw Error(`Invalid TSF compact metadata type ${e}`);return i[e]||(i[e]=1,r[e]=n[e],r[e]=p(n[e],t,a)),r[e]};return a}function l(e,t){let n,r,i,a,o=s=>{if(!n){let[s,c]=f(e);if(!Array.isArray(s))throw Error(`Invalid TSF compact metadata registry`);n=s,i=Array.from({length:s.length}),a=new Uint8Array(s.length),r=m(c,t,o)}if(!Number.isSafeInteger(s)||s<0||s>=n.length)throw Error(`Invalid TSF compact metadata type ${s}`);return a[s]||(a[s]=1,i[s]=n[s],i[s]=p(n[s],t,o,r)),i[s]};return o}function u(e,t,n,r){let[i,a,o]=r===void 0?[e,t,n]:[()=>e(t),n,r],s;try{let e=i();e&&typeof e==`object`&&(s=e)}catch{}let c=s?.__tsfTypeAliases?.[a];return c&&typeof c==`object`?{...c,typeName:o}:{kind:16,typeName:o,classType:()=>s?.[a]}}function d(t){let n=JSON.parse(t);if(!Array.isArray(n)||n.length!==2||n[0]!==e)throw Error(`Unsupported TSF compact metadata format`);return n[1]}function f(e){let t=JSON.parse(e);if(!Array.isArray(t)||t.length!==3||t[0]!==2||!Array.isArray(t[2]))throw Error(`Unsupported TSF compact metadata format`);return[t[1],t[2]]}function p(e,o,s,c){if(!e||typeof e!=`object`)return e;if(v(e))return g(o,e[t]);if(y(e)){let t=e[n],[r,i]=t.length===2?t:[t[0],t[2]],a=_(o,r,t.length===3?t[1]:void 0);return()=>a()?.[i]}if(b(e)){let t=e[r],[n,i,a]=t.length===3?t:[t[0],t[2],t[3]];return u(_(o,n,t.length===4?t[1]:void 0),i,a)}if(x(e)){if(!s)throw Error(`Missing TSF compact metadata type registry`);return s(e[i])}if(S(e)){if(!c)throw Error(`Missing TSF compact metadata node registry`);return c(e[a])}if(Array.isArray(e)){for(let t=0;t<e.length;t++)e[t]=p(e[t],o,s,c);return e}let l=e;for(let e of Object.keys(l))l[e]=p(l[e],o,s,c);return l}function m(e,t,n){let r=Array.from({length:e.length}),i=new Uint8Array(e.length),a=o=>{if(!Number.isSafeInteger(o)||o<0||o>=e.length)throw Error(`Invalid TSF compact metadata node ${o}`);return i[o]||(i[o]=1,r[o]=e[o],r[o]=p(e[o],t,n,a)),r[o]};return a}function h(e){let t={},n=!1,r=()=>{if(n)return;let r=e();if(!r||typeof r!=`object`)throw Error(`Invalid TSF compact metadata root`);for(let e of Reflect.ownKeys(r)){if(Object.prototype.hasOwnProperty.call(t,e))continue;let n=Object.getOwnPropertyDescriptor(r,e);n&&Object.defineProperty(t,e,n)}n=!0};return new Proxy(t,{get(e,t,n){return r(),Reflect.get(e,t,n)},set(e,t,n){return Reflect.set(e,t,n,e)},has(e,t){return r(),Reflect.has(e,t)},ownKeys(e){return r(),Reflect.ownKeys(e)},getOwnPropertyDescriptor(e,t){return r(),Reflect.getOwnPropertyDescriptor(e,t)},defineProperty(e,t,n){return Reflect.defineProperty(e,t,n)},deleteProperty(e,t){return r(),Reflect.deleteProperty(e,t)},getPrototypeOf(e){return r(),Reflect.getPrototypeOf(e)},setPrototypeOf(e,t){return r(),Reflect.setPrototypeOf(e,t)},isExtensible(e){return Reflect.isExtensible(e)},preventExtensions(e){return r(),Reflect.preventExtensions(e)}})}function g(e,t){if(t<0||t>=e.length)throw Error(`Invalid TSF compact metadata reference ${t}`);return e[t]}function _(e,t,n){let r=g(e,t);if(typeof r!=`function`)throw Error(`Invalid TSF compact metadata module loader ${t}`);return n===void 0?r:()=>{try{return r(n)}catch{return}}}function v(e){if(Array.isArray(e))return!1;let n=Object.keys(e);return n.length===1&&n[0]===t&&Number.isSafeInteger(e[t])}function y(e){if(Array.isArray(e))return!1;let t=Object.keys(e),r=e[n];return t.length===1&&t[0]===n&&Array.isArray(r)&&(r.length===2||r.length===3)&&Number.isSafeInteger(r[0])&&typeof r[1]==`string`&&(r.length===2||typeof r[2]==`string`)}function b(e){if(Array.isArray(e))return!1;let t=Object.keys(e),n=e[r];return t.length===1&&t[0]===r&&Array.isArray(n)&&(n.length===3||n.length===4)&&Number.isSafeInteger(n[0])&&typeof n[1]==`string`&&typeof n[2]==`string`&&(n.length===3||typeof n[3]==`string`)}function x(e){if(Array.isArray(e))return!1;let t=Object.keys(e);return t.length===1&&t[0]===i&&Number.isSafeInteger(e[i])}function S(e){if(Array.isArray(e))return!1;let t=Object.keys(e);return t.length===1&&t[0]===a&&Number.isSafeInteger(e[a])}exports.createCompactMetadataRegistryV1=c,exports.createCompactMetadataRegistryV2=l,exports.decodeCompactMetadataV1=o,exports.decodeCompactMetadataV2=s,exports.resolveCompactMetadataAliasV1=u;
|
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
//#region src/reflection/compact-metadata.ts
|
|
2
|
-
var e = "$tsf", t = "$tsfImport", n = "$tsfAlias", r = "$tsfType";
|
|
3
|
-
function
|
|
4
|
-
return
|
|
2
|
+
var e = "$tsf", t = "$tsfImport", n = "$tsfAlias", r = "$tsfType", i = "$tsfNode";
|
|
3
|
+
function a(e, t, n) {
|
|
4
|
+
return f(u(e), t, n);
|
|
5
5
|
}
|
|
6
|
-
function
|
|
7
|
-
|
|
6
|
+
function o(e, t, n) {
|
|
7
|
+
return m(() => {
|
|
8
|
+
let [r, i] = d(e);
|
|
9
|
+
return f(r, t, n, p(i, t, n));
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function s(e, t) {
|
|
13
|
+
let n = u(e);
|
|
8
14
|
if (!Array.isArray(n)) throw Error("Invalid TSF compact metadata registry");
|
|
9
|
-
let r = Array(n.length), i = new Uint8Array(n.length), a = (e) => {
|
|
15
|
+
let r = Array.from({ length: n.length }), i = new Uint8Array(n.length), a = (e) => {
|
|
10
16
|
if (!Number.isSafeInteger(e) || e < 0 || e >= n.length) throw Error(`Invalid TSF compact metadata type ${e}`);
|
|
11
|
-
return i[e] || (i[e] = 1, r[e] = n[e], r[e] =
|
|
17
|
+
return i[e] || (i[e] = 1, r[e] = n[e], r[e] = f(n[e], t, a)), r[e];
|
|
12
18
|
};
|
|
13
19
|
return a;
|
|
14
20
|
}
|
|
15
|
-
function
|
|
21
|
+
function c(e, t) {
|
|
22
|
+
let n, r, i, a, o = (s) => {
|
|
23
|
+
if (!n) {
|
|
24
|
+
let [s, c] = d(e);
|
|
25
|
+
if (!Array.isArray(s)) throw Error("Invalid TSF compact metadata registry");
|
|
26
|
+
n = s, i = Array.from({ length: s.length }), a = new Uint8Array(s.length), r = p(c, t, o);
|
|
27
|
+
}
|
|
28
|
+
if (!Number.isSafeInteger(s) || s < 0 || s >= n.length) throw Error(`Invalid TSF compact metadata type ${s}`);
|
|
29
|
+
return a[s] || (a[s] = 1, i[s] = n[s], i[s] = f(n[s], t, o, r)), i[s];
|
|
30
|
+
};
|
|
31
|
+
return o;
|
|
32
|
+
}
|
|
33
|
+
function l(e, t, n, r) {
|
|
16
34
|
let [i, a, o] = r === void 0 ? [
|
|
17
35
|
e,
|
|
18
36
|
t,
|
|
@@ -36,44 +54,108 @@ function o(e, t, n, r) {
|
|
|
36
54
|
classType: () => s?.[a]
|
|
37
55
|
};
|
|
38
56
|
}
|
|
39
|
-
function
|
|
57
|
+
function u(e) {
|
|
40
58
|
let t = JSON.parse(e);
|
|
41
59
|
if (!Array.isArray(t) || t.length !== 2 || t[0] !== 1) throw Error("Unsupported TSF compact metadata format");
|
|
42
60
|
return t[1];
|
|
43
61
|
}
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
function d(e) {
|
|
63
|
+
let t = JSON.parse(e);
|
|
64
|
+
if (!Array.isArray(t) || t.length !== 3 || t[0] !== 2 || !Array.isArray(t[2])) throw Error("Unsupported TSF compact metadata format");
|
|
65
|
+
return [t[1], t[2]];
|
|
66
|
+
}
|
|
67
|
+
function f(a, o, s, c) {
|
|
68
|
+
if (!a || typeof a != "object") return a;
|
|
69
|
+
if (_(a)) return h(o, a[e]);
|
|
70
|
+
if (v(a)) {
|
|
71
|
+
let e = a[t], [n, r] = e.length === 2 ? e : [e[0], e[2]], i = g(o, n, e.length === 3 ? e[1] : void 0);
|
|
72
|
+
return () => i()?.[r];
|
|
50
73
|
}
|
|
51
|
-
if (
|
|
52
|
-
let e =
|
|
74
|
+
if (y(a)) {
|
|
75
|
+
let e = a[n], [t, r, i] = e.length === 3 ? e : [
|
|
53
76
|
e[0],
|
|
54
77
|
e[2],
|
|
55
78
|
e[3]
|
|
56
79
|
];
|
|
57
|
-
return
|
|
80
|
+
return l(g(o, t, e.length === 4 ? e[1] : void 0), r, i);
|
|
58
81
|
}
|
|
59
|
-
if (
|
|
82
|
+
if (b(a)) {
|
|
60
83
|
if (!s) throw Error("Missing TSF compact metadata type registry");
|
|
61
|
-
return s(
|
|
84
|
+
return s(a[r]);
|
|
85
|
+
}
|
|
86
|
+
if (x(a)) {
|
|
87
|
+
if (!c) throw Error("Missing TSF compact metadata node registry");
|
|
88
|
+
return c(a[i]);
|
|
62
89
|
}
|
|
63
|
-
if (Array.isArray(
|
|
64
|
-
for (let e = 0; e <
|
|
65
|
-
return
|
|
90
|
+
if (Array.isArray(a)) {
|
|
91
|
+
for (let e = 0; e < a.length; e++) a[e] = f(a[e], o, s, c);
|
|
92
|
+
return a;
|
|
66
93
|
}
|
|
67
|
-
let
|
|
68
|
-
for (let e of Object.keys(
|
|
69
|
-
return
|
|
94
|
+
let u = a;
|
|
95
|
+
for (let e of Object.keys(u)) u[e] = f(u[e], o, s, c);
|
|
96
|
+
return u;
|
|
97
|
+
}
|
|
98
|
+
function p(e, t, n) {
|
|
99
|
+
let r = Array.from({ length: e.length }), i = new Uint8Array(e.length), a = (o) => {
|
|
100
|
+
if (!Number.isSafeInteger(o) || o < 0 || o >= e.length) throw Error(`Invalid TSF compact metadata node ${o}`);
|
|
101
|
+
return i[o] || (i[o] = 1, r[o] = e[o], r[o] = f(e[o], t, n, a)), r[o];
|
|
102
|
+
};
|
|
103
|
+
return a;
|
|
70
104
|
}
|
|
71
|
-
function
|
|
105
|
+
function m(e) {
|
|
106
|
+
let t = {}, n = !1, r = () => {
|
|
107
|
+
if (n) return;
|
|
108
|
+
let r = e();
|
|
109
|
+
if (!r || typeof r != "object") throw Error("Invalid TSF compact metadata root");
|
|
110
|
+
for (let e of Reflect.ownKeys(r)) {
|
|
111
|
+
if (Object.prototype.hasOwnProperty.call(t, e)) continue;
|
|
112
|
+
let n = Object.getOwnPropertyDescriptor(r, e);
|
|
113
|
+
n && Object.defineProperty(t, e, n);
|
|
114
|
+
}
|
|
115
|
+
n = !0;
|
|
116
|
+
};
|
|
117
|
+
return new Proxy(t, {
|
|
118
|
+
get(e, t, n) {
|
|
119
|
+
return r(), Reflect.get(e, t, n);
|
|
120
|
+
},
|
|
121
|
+
set(e, t, n) {
|
|
122
|
+
return Reflect.set(e, t, n, e);
|
|
123
|
+
},
|
|
124
|
+
has(e, t) {
|
|
125
|
+
return r(), Reflect.has(e, t);
|
|
126
|
+
},
|
|
127
|
+
ownKeys(e) {
|
|
128
|
+
return r(), Reflect.ownKeys(e);
|
|
129
|
+
},
|
|
130
|
+
getOwnPropertyDescriptor(e, t) {
|
|
131
|
+
return r(), Reflect.getOwnPropertyDescriptor(e, t);
|
|
132
|
+
},
|
|
133
|
+
defineProperty(e, t, n) {
|
|
134
|
+
return Reflect.defineProperty(e, t, n);
|
|
135
|
+
},
|
|
136
|
+
deleteProperty(e, t) {
|
|
137
|
+
return r(), Reflect.deleteProperty(e, t);
|
|
138
|
+
},
|
|
139
|
+
getPrototypeOf(e) {
|
|
140
|
+
return r(), Reflect.getPrototypeOf(e);
|
|
141
|
+
},
|
|
142
|
+
setPrototypeOf(e, t) {
|
|
143
|
+
return r(), Reflect.setPrototypeOf(e, t);
|
|
144
|
+
},
|
|
145
|
+
isExtensible(e) {
|
|
146
|
+
return Reflect.isExtensible(e);
|
|
147
|
+
},
|
|
148
|
+
preventExtensions(e) {
|
|
149
|
+
return r(), Reflect.preventExtensions(e);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function h(e, t) {
|
|
72
154
|
if (t < 0 || t >= e.length) throw Error(`Invalid TSF compact metadata reference ${t}`);
|
|
73
155
|
return e[t];
|
|
74
156
|
}
|
|
75
|
-
function
|
|
76
|
-
let r =
|
|
157
|
+
function g(e, t, n) {
|
|
158
|
+
let r = h(e, t);
|
|
77
159
|
if (typeof r != "function") throw Error(`Invalid TSF compact metadata module loader ${t}`);
|
|
78
160
|
return n === void 0 ? r : () => {
|
|
79
161
|
try {
|
|
@@ -83,25 +165,30 @@ function u(e, t, n) {
|
|
|
83
165
|
}
|
|
84
166
|
};
|
|
85
167
|
}
|
|
86
|
-
function
|
|
168
|
+
function _(t) {
|
|
87
169
|
if (Array.isArray(t)) return !1;
|
|
88
170
|
let n = Object.keys(t);
|
|
89
171
|
return n.length === 1 && n[0] === e && Number.isSafeInteger(t[e]);
|
|
90
172
|
}
|
|
91
|
-
function
|
|
173
|
+
function v(e) {
|
|
92
174
|
if (Array.isArray(e)) return !1;
|
|
93
175
|
let n = Object.keys(e), r = e[t];
|
|
94
176
|
return n.length === 1 && n[0] === t && Array.isArray(r) && (r.length === 2 || r.length === 3) && Number.isSafeInteger(r[0]) && typeof r[1] == "string" && (r.length === 2 || typeof r[2] == "string");
|
|
95
177
|
}
|
|
96
|
-
function
|
|
178
|
+
function y(e) {
|
|
97
179
|
if (Array.isArray(e)) return !1;
|
|
98
180
|
let t = Object.keys(e), r = e[n];
|
|
99
181
|
return t.length === 1 && t[0] === n && Array.isArray(r) && (r.length === 3 || r.length === 4) && Number.isSafeInteger(r[0]) && typeof r[1] == "string" && typeof r[2] == "string" && (r.length === 3 || typeof r[3] == "string");
|
|
100
182
|
}
|
|
101
|
-
function
|
|
183
|
+
function b(e) {
|
|
102
184
|
if (Array.isArray(e)) return !1;
|
|
103
185
|
let t = Object.keys(e);
|
|
104
186
|
return t.length === 1 && t[0] === r && Number.isSafeInteger(e[r]);
|
|
105
187
|
}
|
|
188
|
+
function x(e) {
|
|
189
|
+
if (Array.isArray(e)) return !1;
|
|
190
|
+
let t = Object.keys(e);
|
|
191
|
+
return t.length === 1 && t[0] === i && Number.isSafeInteger(e[i]);
|
|
192
|
+
}
|
|
106
193
|
//#endregion
|
|
107
|
-
export {
|
|
194
|
+
export { s as createCompactMetadataRegistryV1, c as createCompactMetadataRegistryV2, a as decodeCompactMetadataV1, o as decodeCompactMetadataV2, l as resolveCompactMetadataAliasV1 };
|