typia 14.0.0 → 14.0.2
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/internal/_createStandardSchema.d.ts +1 -2
- package/lib/internal/_createStandardSchema.js.map +1 -1
- package/lib/internal/_createStandardSchema.mjs.map +1 -1
- package/lib/module.d.ts +1 -2
- package/lib/module.js.map +1 -1
- package/lib/module.mjs.map +1 -1
- package/lib/re-exports.d.ts +1 -1
- package/lib/re-exports.js.map +1 -1
- package/lib/transformers/NoTransformConfigurationError.js +19 -4
- package/lib/transformers/NoTransformConfigurationError.js.map +1 -1
- package/lib/transformers/NoTransformConfigurationError.mjs +12 -6
- package/lib/transformers/NoTransformConfigurationError.mjs.map +1 -1
- package/native/cmd/ttsc-typia/create_assert_error_factory_arity_test.go +5 -2
- package/native/cmd/ttsc-typia/dependency_collector_virtual_scheme_test.go +52 -0
- package/native/cmd/ttsc-typia/json_schema_nonsensible_intersection_diagnostic_test.go +80 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_argument_transform_test.go +177 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_barrel_transform_test.go +115 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_inference_transform_test.go +285 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_shape_transform_test.go +117 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_untransformed_barrel_transform_test.go +121 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_diagnostic_transform_test.go +116 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_envelope_transform_test.go +115 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_inferred_type_transform_test.go +127 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_replaced_library_transform_test.go +153 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_untouched_reprint_transform_test.go +155 -0
- package/native/cmd/ttsc-typia/project_dependencies_computed_key_transform_test.go +218 -0
- package/native/cmd/ttsc-typia/project_dependencies_custom_lib_name_transform_test.go +6 -5
- package/native/cmd/ttsc-typia/project_dependencies_enum_member_value_transform_test.go +131 -0
- package/native/cmd/ttsc-typia/project_dependencies_inferred_declaration_transform_test.go +159 -0
- package/native/cmd/ttsc-typia/project_dependencies_jsdoc_typedef_transform_test.go +134 -0
- package/native/cmd/ttsc-typia/project_dependencies_named_tuple_member_transform_test.go +123 -0
- package/native/cmd/ttsc-typia/project_dependencies_qualified_barrel_transform_test.go +141 -0
- package/native/cmd/ttsc-typia/project_dependencies_type_parameter_default_transform_test.go +127 -0
- package/native/cmd/ttsc-typia/transform.go +193 -19
- package/native/core/schemas/metadata/MetadataDependency.go +613 -30
- package/native/transform/CallExpressionTransformer.go +16 -1
- package/package.json +4 -5
- package/src/internal/_createStandardSchema.ts +1 -2
- package/src/module.ts +6 -2
- package/src/re-exports.ts +13 -0
- package/src/transformers/NoTransformConfigurationError.ts +19 -4
|
@@ -103,7 +103,7 @@ func runTransform(args []string) int {
|
|
|
103
103
|
fmt.Fprintln(stderr, "ttsc-typia transform: --out requires --file")
|
|
104
104
|
return 2
|
|
105
105
|
}
|
|
106
|
-
return runTransformProject(prog, cwd, typiaTransform, &transformDiags)
|
|
106
|
+
return runTransformProject(prog, cwd, typiaTransform, &transformDiags, &extras)
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
absFile := *file
|
|
@@ -190,11 +190,25 @@ func runTransformSingle(
|
|
|
190
190
|
// dependencies[F]), so graph is added alongside dependencies, not a replacement.
|
|
191
191
|
// Every section keys through driver.TransformOutputKey, so the consumer joins
|
|
192
192
|
// them by key.
|
|
193
|
+
//
|
|
194
|
+
// A third section, `dependenciesComplete`, names the files whose `dependencies`
|
|
195
|
+
// entry is the whole story, and for those the consumer stops unioning: it
|
|
196
|
+
// derives dependencies[F] ∪ configs ∪ candidates and drops reach(edges, F) and
|
|
197
|
+
// globals. That is the difference between re-validating the reference closure
|
|
198
|
+
// of a file and re-validating the handful of declarations typia read, paid once
|
|
199
|
+
// per delivered module, and for the majority of a project's files -- the ones
|
|
200
|
+
// with no typia call at all -- between the closure and nothing.
|
|
201
|
+
//
|
|
202
|
+
// The declaration transfers responsibility, so it is made per file and only
|
|
203
|
+
// where the collector could bound the file's inputs; the dependency listener
|
|
204
|
+
// and the diagnostic report this function wires are what decide that
|
|
205
|
+
// (samchon/typia#2357). See transformDependencyCollector.Unbound.
|
|
193
206
|
func runTransformProject(
|
|
194
207
|
prog *driver.Program,
|
|
195
208
|
cwd string,
|
|
196
209
|
typiaTransform driver.PluginTransform,
|
|
197
210
|
transformDiags *[]typiaTransformDiagnostic,
|
|
211
|
+
extras *nativecontext.ITypiaContext_Extras,
|
|
198
212
|
) int {
|
|
199
213
|
out := transformProjectOutput{
|
|
200
214
|
Diagnostics: []transformCompilerDiagnostic{},
|
|
@@ -209,8 +223,27 @@ func runTransformProject(
|
|
|
209
223
|
sf := prog.SourceFile(fileName)
|
|
210
224
|
return sf != nil && prog.TSProgram.IsLibFile(sf)
|
|
211
225
|
})
|
|
212
|
-
|
|
226
|
+
// Only this host declares completeness, which is why only this host asks the
|
|
227
|
+
// analysis to admit what it could not bound: every such admission costs one
|
|
228
|
+
// file its declaration and nothing else.
|
|
229
|
+
schemametadata.MetadataDependency_listen(prog.Checker, schemametadata.MetadataDependency_IListener{
|
|
230
|
+
File: collector.Touch,
|
|
231
|
+
Callee: collector.TouchCallee,
|
|
232
|
+
Unbounded: collector.Unbound,
|
|
233
|
+
})
|
|
213
234
|
defer schemametadata.MetadataDependency_release(prog.Checker)
|
|
235
|
+
// A diagnostic means typia could not finish lowering a call in the file being
|
|
236
|
+
// transformed, so what the analysis consulted before giving up is not that
|
|
237
|
+
// file's whole input set: an edit to a declaration it never reached could make
|
|
238
|
+
// the same call succeed and publish different text. The build fails either
|
|
239
|
+
// way, but a false claim is still false, so withhold the declaration rather
|
|
240
|
+
// than reason about how far the analysis got. The transformer reads `extras`
|
|
241
|
+
// on every call, so wrapping it through the pointer reaches the loop below.
|
|
242
|
+
reportDiagnostic := extras.AddDiagnostic
|
|
243
|
+
extras.AddDiagnostic = func(diag *nativecontext.ITypiaDiagnostic) int {
|
|
244
|
+
collector.Unbound()
|
|
245
|
+
return reportDiagnostic(diag)
|
|
246
|
+
}
|
|
214
247
|
for _, sf := range prog.SourceFiles() {
|
|
215
248
|
if sf.IsDeclarationFile {
|
|
216
249
|
continue
|
|
@@ -221,8 +254,16 @@ func runTransformProject(
|
|
|
221
254
|
}
|
|
222
255
|
collector.Begin(key)
|
|
223
256
|
out.TypeScript[key] = transformFileToTypeScript(prog, typiaTransform, sf)
|
|
257
|
+
collector.End()
|
|
224
258
|
}
|
|
225
259
|
out.Dependencies = collector.ToJSON()
|
|
260
|
+
// The config chain is the one input that stays universal for a declared file,
|
|
261
|
+
// and it reaches the consumer through this same envelope's graph. Declaring
|
|
262
|
+
// completeness without a graph would leave nothing universal behind, so a
|
|
263
|
+
// tsconfig edit would stop invalidating the files the declaration narrowed.
|
|
264
|
+
if out.Graph != nil {
|
|
265
|
+
out.DependenciesComplete = collector.ToCompleteJSON(out.TypeScript)
|
|
266
|
+
}
|
|
226
267
|
for _, diag := range *transformDiags {
|
|
227
268
|
out.Diagnostics = append(out.Diagnostics, transformDiagnosticToCompilerDiagnostic(diag))
|
|
228
269
|
}
|
|
@@ -359,24 +400,62 @@ type transformProjectOutput struct {
|
|
|
359
400
|
// files are excluded (toolchain-versioned, not project inputs);
|
|
360
401
|
// `node_modules` declaration files are included.
|
|
361
402
|
Dependencies map[string][]string `json:"dependencies,omitempty"`
|
|
403
|
+
// DependenciesComplete lists the TypeScript keys whose Dependencies entry is
|
|
404
|
+
// exhaustive: nothing outside that entry, the file itself, and the universal
|
|
405
|
+
// config chain can change the file's transformed text. The consumer stops
|
|
406
|
+
// widening those files with the reference closure and the global-scope set.
|
|
407
|
+
//
|
|
408
|
+
// Unlisted is always the safe answer, so the list carries only what the
|
|
409
|
+
// collector could bound. An older ttsc ignores the field; 0.19.3 and newer
|
|
410
|
+
// narrow on it.
|
|
411
|
+
DependenciesComplete []string `json:"dependenciesComplete,omitempty"`
|
|
362
412
|
}
|
|
363
413
|
|
|
364
414
|
// transformDependencyCollector accumulates the consulted-declaration files the
|
|
365
415
|
// metadata dependency listener reports while one project file is transformed,
|
|
366
|
-
// attributing them to that file's envelope key
|
|
416
|
+
// attributing them to that file's envelope key, and decides which of those keys
|
|
417
|
+
// may be declared complete.
|
|
367
418
|
type transformDependencyCollector struct {
|
|
368
419
|
cwd string
|
|
369
420
|
current string
|
|
370
421
|
files map[string]map[string]bool
|
|
422
|
+
// unbounded holds the keys withheld from the completeness declaration. It is
|
|
423
|
+
// a set of exclusions rather than a set of admissions because every path that
|
|
424
|
+
// learns a file cannot be bounded runs while that file is being transformed,
|
|
425
|
+
// whereas nothing ever proves the opposite: a file is declarable exactly when
|
|
426
|
+
// no such path fired for it.
|
|
427
|
+
unbounded map[string]bool
|
|
371
428
|
// isLibraryFile reports the compiler's own classification of a file as a
|
|
372
429
|
// default library. Classification must come from the program, never from a
|
|
373
430
|
// filename pattern: a project's own ambient declaration file may legitimately
|
|
374
431
|
// be named `lib.custom.d.ts`, and dropping it by basename silently loses
|
|
375
432
|
// cache invalidation for the types it declares (samchon/typia#2108).
|
|
376
433
|
isLibraryFile func(fileName string) bool
|
|
377
|
-
// values memoizes fileName -> envelope value
|
|
378
|
-
//
|
|
379
|
-
values map[string]
|
|
434
|
+
// values memoizes fileName -> rendered envelope value: the listener reports
|
|
435
|
+
// the same declaration files repeatedly across call sites.
|
|
436
|
+
values map[string]transformDependencyValue
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// transformDependencyBundledScheme is the prefix tsgo gives its embedded default
|
|
440
|
+
// libraries, and the one `driver.NewTransformGraph` drops from the host-owned
|
|
441
|
+
// reference graph.
|
|
442
|
+
const transformDependencyBundledScheme = "bundled:///"
|
|
443
|
+
|
|
444
|
+
// transformDependencyValue is one reported file rendered for the envelope: its
|
|
445
|
+
// key, or the reason it was dropped. The reasons differ in what they cost a
|
|
446
|
+
// completeness declaration, so they cannot both collapse to an empty value.
|
|
447
|
+
type transformDependencyValue struct {
|
|
448
|
+
// key is the envelope value, empty when the file was dropped.
|
|
449
|
+
key string
|
|
450
|
+
// withhold marks a file this envelope cannot report but the host-owned bound
|
|
451
|
+
// still carries, so narrowing to the reported list would lose it.
|
|
452
|
+
withhold bool
|
|
453
|
+
// libraryOnly marks a withhold whose only cause is the compiler classifying
|
|
454
|
+
// the file as a default library. Such a file can change a consulted type and
|
|
455
|
+
// so a generated validator, but never which declaration a call resolves to,
|
|
456
|
+
// which is why the identity channel drops it without withholding
|
|
457
|
+
// (samchon/typia#2361).
|
|
458
|
+
libraryOnly bool
|
|
380
459
|
}
|
|
381
460
|
|
|
382
461
|
func newTransformDependencyCollector(
|
|
@@ -387,7 +466,8 @@ func newTransformDependencyCollector(
|
|
|
387
466
|
cwd: cwd,
|
|
388
467
|
isLibraryFile: isLibraryFile,
|
|
389
468
|
files: map[string]map[string]bool{},
|
|
390
|
-
|
|
469
|
+
unbounded: map[string]bool{},
|
|
470
|
+
values: map[string]transformDependencyValue{},
|
|
391
471
|
}
|
|
392
472
|
}
|
|
393
473
|
|
|
@@ -396,11 +476,61 @@ func (collector *transformDependencyCollector) Begin(key string) {
|
|
|
396
476
|
collector.current = key
|
|
397
477
|
}
|
|
398
478
|
|
|
479
|
+
// End closes the attribution window Begin opened. Nothing consults the checker
|
|
480
|
+
// between two files today, so this changes no output; it is what keeps that
|
|
481
|
+
// true, because a touch that arrives outside a window is dropped rather than
|
|
482
|
+
// charged -- or worse, withheld -- against whichever file happened to run last.
|
|
483
|
+
func (collector *transformDependencyCollector) End() {
|
|
484
|
+
collector.current = ""
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Unbound withholds the completeness declaration from the file being
|
|
488
|
+
// transformed. The file keeps its reported dependencies and falls back to the
|
|
489
|
+
// host-owned reference-closure bound, which is what an unlisted file gets and
|
|
490
|
+
// is always sound. Its callers name the reasons: an input the analysis could
|
|
491
|
+
// only read from an inferred position, a consulted on-disk default library, and
|
|
492
|
+
// a call typia could not lower.
|
|
493
|
+
func (collector *transformDependencyCollector) Unbound() {
|
|
494
|
+
if collector.current == "" {
|
|
495
|
+
return
|
|
496
|
+
}
|
|
497
|
+
collector.unbounded[collector.current] = true
|
|
498
|
+
}
|
|
499
|
+
|
|
399
500
|
// Touch records one consulted declaration file for the current key. Default
|
|
400
501
|
// library files, virtual URI sources (e.g. tsgo's `bundled:///` libraries),
|
|
401
502
|
// and the transformed file itself are dropped so the envelope carries only
|
|
402
503
|
// actionable project inputs.
|
|
504
|
+
//
|
|
505
|
+
// A drop the host-owned bound does not share also withholds the current file's
|
|
506
|
+
// completeness declaration: the graph still carries that file, so a narrowed
|
|
507
|
+
// file would stop watching an input the default bound watches.
|
|
403
508
|
func (collector *transformDependencyCollector) Touch(fileName string) {
|
|
509
|
+
collector.touch(fileName, true)
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// TouchCallee records one file reached while deciding WHICH declaration a call
|
|
513
|
+
// resolves to, and does not let a default library withhold the current file.
|
|
514
|
+
//
|
|
515
|
+
// A default library is dropped from the reported list either way -- that
|
|
516
|
+
// contract is samchon/typia#2108's -- but the withholding beside it belongs to
|
|
517
|
+
// the type channel alone. Under `libReplacement` a replaced library can change
|
|
518
|
+
// a generated validator, so a file that consulted one has to give up its
|
|
519
|
+
// declaration. It can never change which declaration a call resolves to:
|
|
520
|
+
// callExpressionTransformer_targetModule recognizes typia's own calls by a path
|
|
521
|
+
// ending in `/typia/lib/<file>.d.ts` or `/typia/src/<file>.ts`, and a file the
|
|
522
|
+
// compiler classifies as a default library satisfies neither wherever it sits
|
|
523
|
+
// on disk. Withholding there cost a file its declaration for calling
|
|
524
|
+
// `table.get(...)`, and under `noembed` -- where every library is a real file --
|
|
525
|
+
// for calling anything at all (samchon/typia#2361).
|
|
526
|
+
//
|
|
527
|
+
// A virtual non-`bundled:///` scheme still withholds on both channels: that drop
|
|
528
|
+
// is about being unwatchable, not about being a library.
|
|
529
|
+
func (collector *transformDependencyCollector) TouchCallee(fileName string) {
|
|
530
|
+
collector.touch(fileName, false)
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
func (collector *transformDependencyCollector) touch(fileName string, library bool) {
|
|
404
534
|
if collector.current == "" {
|
|
405
535
|
return
|
|
406
536
|
}
|
|
@@ -409,7 +539,10 @@ func (collector *transformDependencyCollector) Touch(fileName string) {
|
|
|
409
539
|
value = collector.value(fileName)
|
|
410
540
|
collector.values[fileName] = value
|
|
411
541
|
}
|
|
412
|
-
if value
|
|
542
|
+
if value.withhold && (library || value.libraryOnly == false) {
|
|
543
|
+
collector.Unbound()
|
|
544
|
+
}
|
|
545
|
+
if value.key == "" || value.key == collector.current {
|
|
413
546
|
return
|
|
414
547
|
}
|
|
415
548
|
set := collector.files[collector.current]
|
|
@@ -417,19 +550,36 @@ func (collector *transformDependencyCollector) Touch(fileName string) {
|
|
|
417
550
|
set = map[string]bool{}
|
|
418
551
|
collector.files[collector.current] = set
|
|
419
552
|
}
|
|
420
|
-
set[value] = true
|
|
553
|
+
set[value.key] = true
|
|
421
554
|
}
|
|
422
555
|
|
|
423
|
-
// value renders one reported file as its envelope value, or
|
|
424
|
-
//
|
|
425
|
-
//
|
|
426
|
-
// libraries
|
|
427
|
-
//
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
556
|
+
// value renders one reported file as its envelope value, or records why it must
|
|
557
|
+
// be dropped.
|
|
558
|
+
//
|
|
559
|
+
// tsgo's embedded libraries under `bundled:///` are nobody's input:
|
|
560
|
+
// `driver.NewTransformGraph` skips that exact prefix, so dropping them leaves
|
|
561
|
+
// the reported list and the host-owned bound in agreement and costs a
|
|
562
|
+
// completeness declaration nothing. Any other URI scheme is unwatchable for us
|
|
563
|
+
// but still reaches the graph, so it is dropped AND withheld -- the asymmetry
|
|
564
|
+
// only runs in the safe direction.
|
|
565
|
+
//
|
|
566
|
+
// A file the compiler classifies as a default library is a toolchain input
|
|
567
|
+
// rather than a project input, which is why the envelope has never reported one.
|
|
568
|
+
// Under `noembed` or `libReplacement` it is nevertheless a real path that
|
|
569
|
+
// `graph.globals` carries, so the default bound watches it while a narrowed file
|
|
570
|
+
// would not. Keep dropping it from the reported list -- that contract is
|
|
571
|
+
// #2108's -- and withhold the declaration from the file that consulted it.
|
|
572
|
+
func (collector *transformDependencyCollector) value(fileName string) transformDependencyValue {
|
|
573
|
+
if strings.HasPrefix(fileName, transformDependencyBundledScheme) {
|
|
574
|
+
return transformDependencyValue{}
|
|
575
|
+
}
|
|
576
|
+
if strings.Contains(fileName, "://") {
|
|
577
|
+
return transformDependencyValue{withhold: true}
|
|
578
|
+
}
|
|
579
|
+
if collector.isLibraryFile(fileName) {
|
|
580
|
+
return transformDependencyValue{withhold: true, libraryOnly: true}
|
|
581
|
+
}
|
|
582
|
+
return transformDependencyValue{key: driver.TransformOutputKey(collector.cwd, fileName)}
|
|
433
583
|
}
|
|
434
584
|
|
|
435
585
|
// ToJSON renders the collected sets as the envelope's `dependencies` map with
|
|
@@ -456,6 +606,30 @@ func (collector *transformDependencyCollector) ToJSON() map[string][]string {
|
|
|
456
606
|
return output
|
|
457
607
|
}
|
|
458
608
|
|
|
609
|
+
// ToCompleteJSON renders the envelope's `dependenciesComplete` list: every key
|
|
610
|
+
// the transform published except the ones the collector could not bound.
|
|
611
|
+
//
|
|
612
|
+
// The published map is the input rather than the entries of ToJSON. A file typia
|
|
613
|
+
// never touched reports no dependency at all, and that empty entry is the
|
|
614
|
+
// strongest claim in the envelope -- nothing outside the file can change a
|
|
615
|
+
// faithful re-print -- so reading the dependency map instead would drop the
|
|
616
|
+
// majority of the narrowing on the floor. Taking the same map the consumer keys
|
|
617
|
+
// on also makes the list a subset of it by construction.
|
|
618
|
+
func (collector *transformDependencyCollector) ToCompleteJSON(published map[string]string) []string {
|
|
619
|
+
output := make([]string, 0, len(published))
|
|
620
|
+
for key := range published {
|
|
621
|
+
if collector.unbounded[key] {
|
|
622
|
+
continue
|
|
623
|
+
}
|
|
624
|
+
output = append(output, key)
|
|
625
|
+
}
|
|
626
|
+
if len(output) == 0 {
|
|
627
|
+
return nil
|
|
628
|
+
}
|
|
629
|
+
sort.Strings(output)
|
|
630
|
+
return output
|
|
631
|
+
}
|
|
632
|
+
|
|
459
633
|
type transformCompilerDiagnostic struct {
|
|
460
634
|
File *string `json:"file"`
|
|
461
635
|
Category string `json:"category"`
|