ttsc 0.32.0 → 0.32.1
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/TtscCompiler.js +1 -1
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/compiler/internal/ResidentCheckProcess.d.ts +74 -96
- package/lib/compiler/internal/ResidentCheckProcess.js +150 -335
- package/lib/compiler/internal/ResidentCheckProcess.js.map +1 -1
- package/lib/compiler/internal/ResidentCheckProcessHost.d.ts +127 -0
- package/lib/compiler/internal/ResidentCheckProcessHost.js +447 -0
- package/lib/compiler/internal/ResidentCheckProcessHost.js.map +1 -0
- package/lib/compiler/internal/ResidentCheckProcessProtocol.d.ts +64 -0
- package/lib/compiler/internal/ResidentCheckProcessProtocol.js +3 -0
- package/lib/compiler/internal/ResidentCheckProcessProtocol.js.map +1 -0
- package/lib/compiler/internal/build/BuildExecution.d.ts +103 -1
- package/lib/compiler/internal/build/BuildExecution.js +91 -11
- package/lib/compiler/internal/build/BuildExecution.js.map +1 -1
- package/lib/compiler/internal/build/ResidentCheckWatchSession.d.ts +16 -11
- package/lib/compiler/internal/build/ResidentCheckWatchSession.js +37 -21
- package/lib/compiler/internal/build/ResidentCheckWatchSession.js.map +1 -1
- package/lib/compiler/internal/build/RunBuildOptions.d.ts +6 -5
- package/lib/compiler/internal/build/WatchInputPublication.d.ts +59 -0
- package/lib/compiler/internal/build/WatchInputPublication.js +93 -0
- package/lib/compiler/internal/build/WatchInputPublication.js.map +1 -0
- package/lib/compiler/internal/build/runBuild.d.ts +29 -2
- package/lib/compiler/internal/build/runBuild.js +45 -19
- package/lib/compiler/internal/build/runBuild.js.map +1 -1
- package/lib/compiler/internal/buildNativeCompiler.d.ts +2 -0
- package/lib/compiler/internal/buildNativeCompiler.js +1 -0
- package/lib/compiler/internal/buildNativeCompiler.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.js +4 -2
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/project/resolveOwningProjectConfig.d.ts +7 -2
- package/lib/compiler/internal/project/resolveOwningProjectConfig.js +6 -3
- package/lib/compiler/internal/project/resolveOwningProjectConfig.js.map +1 -1
- package/lib/compiler/internal/readEffectiveCompilerOptions.js +1 -1
- package/lib/compiler/internal/readEffectiveCompilerOptions.js.map +1 -1
- package/lib/compiler/internal/resolveBinary.d.ts +1 -0
- package/lib/compiler/internal/resolveBinary.js.map +1 -1
- package/lib/compiler/internal/resolveTsgo.d.ts +6 -0
- package/lib/compiler/internal/resolveTsgo.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.d.ts +28 -1
- package/lib/compiler/internal/runSingleFileEmit.js +120 -86
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.js +8 -2
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +11 -3
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/transformProjectInWorker.d.ts +1 -1
- package/lib/compiler/internal/transformProjectInWorker.js +3 -2
- package/lib/compiler/internal/transformProjectInWorker.js.map +1 -1
- package/lib/internal/workerModuleUrl.d.ts +28 -0
- package/lib/internal/workerModuleUrl.js +40 -0
- package/lib/internal/workerModuleUrl.js.map +1 -0
- package/lib/launcher/internal/buildSingleRootProject.js +2 -1
- package/lib/launcher/internal/buildSingleRootProject.js.map +1 -1
- package/lib/launcher/internal/getCompilerVersionText.js +3 -2
- package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.js +2 -1
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +91 -41
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runtime/CommonJsRuntimeSource.d.ts +10 -6
- package/lib/launcher/internal/runtime/CommonJsRuntimeSource.js +11 -9
- package/lib/launcher/internal/runtime/CommonJsRuntimeSource.js.map +1 -1
- package/lib/launcher/internal/runtime/advertiseTypeScriptExtensions.d.ts +20 -0
- package/lib/launcher/internal/runtime/advertiseTypeScriptExtensions.js +27 -0
- package/lib/launcher/internal/runtime/advertiseTypeScriptExtensions.js.map +1 -0
- package/lib/launcher/internal/runtime/installRuntimeHooks.d.ts +5 -3
- package/lib/launcher/internal/runtime/installRuntimeHooks.js +7 -3
- package/lib/launcher/internal/runtime/installRuntimeHooks.js.map +1 -1
- package/lib/launcher/internal/watch/AsyncWatchTopology.d.ts +113 -0
- package/lib/launcher/internal/watch/AsyncWatchTopology.js +232 -0
- package/lib/launcher/internal/watch/AsyncWatchTopology.js.map +1 -0
- package/lib/launcher/internal/watch/WatchSettlement.d.ts +49 -0
- package/lib/launcher/internal/watch/WatchSettlement.js +70 -0
- package/lib/launcher/internal/watch/WatchSettlement.js.map +1 -0
- package/lib/launcher/internal/watch/WatchTopology.d.ts +29 -1
- package/lib/launcher/internal/watch/WatchTopology.js +86 -10
- package/lib/launcher/internal/watch/WatchTopology.js.map +1 -1
- package/lib/launcher/internal/watch/WatchTopologyWorkerProtocol.d.ts +121 -0
- package/lib/launcher/internal/watch/WatchTopologyWorkerProtocol.js +3 -0
- package/lib/launcher/internal/watch/WatchTopologyWorkerProtocol.js.map +1 -0
- package/lib/launcher/internal/watch/serveWatchTopologyWorker.d.ts +19 -0
- package/lib/launcher/internal/watch/serveWatchTopologyWorker.js +62 -0
- package/lib/launcher/internal/watch/serveWatchTopologyWorker.js.map +1 -0
- package/lib/launcher/internal/watch/watchTopologyWorker.d.ts +1 -0
- package/lib/launcher/internal/watch/watchTopologyWorker.js +22 -0
- package/lib/launcher/internal/watch/watchTopologyWorker.js.map +1 -0
- package/lib/plugin/CapabilityPluginResolver.d.ts +1 -1
- package/lib/plugin/CapabilityPluginResolver.js +3 -2
- package/lib/plugin/CapabilityPluginResolver.js.map +1 -1
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.d.ts +15 -12
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js +13 -11
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js.map +1 -1
- package/lib/plugin/internal/load/PluginPackageResolution.d.ts +2 -2
- package/lib/plugin/internal/load/PluginPackageResolution.js +13 -7
- package/lib/plugin/internal/load/PluginPackageResolution.js.map +1 -1
- package/lib/plugin/internal/load/ProjectPluginEntries.d.ts +23 -7
- package/lib/plugin/internal/load/ProjectPluginEntries.js +36 -14
- package/lib/plugin/internal/load/ProjectPluginEntries.js.map +1 -1
- package/lib/plugin/internal/load/collectProjectHostInputs.d.ts +3 -1
- package/lib/plugin/internal/load/collectProjectHostInputs.js +5 -2
- package/lib/plugin/internal/load/collectProjectHostInputs.js.map +1 -1
- package/lib/plugin/internal/load/hasProjectPluginEntries.d.ts +3 -1
- package/lib/plugin/internal/load/hasProjectPluginEntries.js +4 -2
- package/lib/plugin/internal/load/hasProjectPluginEntries.js.map +1 -1
- package/lib/plugin/internal/load/loadProjectPlugins.d.ts +36 -5
- package/lib/plugin/internal/load/loadProjectPlugins.js +466 -416
- package/lib/plugin/internal/load/loadProjectPlugins.js.map +1 -1
- package/lib/plugin/internal/load/pluginResolutionFailure.d.ts +18 -0
- package/lib/plugin/internal/load/pluginResolutionFailure.js +32 -0
- package/lib/plugin/internal/load/pluginResolutionFailure.js.map +1 -0
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.d.ts +1 -1
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js +3 -2
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js.map +1 -1
- package/lib/structures/ITtscCompilerContext.d.ts +12 -12
- package/lib/structures/ITtscPlugin.d.ts +7 -5
- package/lib/structures/ITtscPluginFactoryContext.d.ts +9 -8
- package/lib/structures/internal/TtscSingleFileEmitOptions.d.ts +12 -6
- package/package.json +9 -9
- package/src/TtscCompiler.ts +1 -1
- package/src/compiler/internal/ResidentCheckProcess.ts +159 -374
- package/src/compiler/internal/ResidentCheckProcessHost.ts +502 -0
- package/src/compiler/internal/ResidentCheckProcessProtocol.ts +53 -0
- package/src/compiler/internal/build/BuildExecution.ts +118 -9
- package/src/compiler/internal/build/ResidentCheckWatchSession.ts +41 -24
- package/src/compiler/internal/build/RunBuildOptions.ts +9 -5
- package/src/compiler/internal/build/WatchInputPublication.ts +106 -0
- package/src/compiler/internal/build/runBuild.ts +58 -34
- package/src/compiler/internal/buildNativeCompiler.ts +4 -0
- package/src/compiler/internal/compileProjectInMemory.ts +8 -2
- package/src/compiler/internal/project/resolveOwningProjectConfig.ts +16 -5
- package/src/compiler/internal/readEffectiveCompilerOptions.ts +1 -1
- package/src/compiler/internal/resolveBinary.ts +4 -1
- package/src/compiler/internal/resolveTsgo.ts +7 -0
- package/src/compiler/internal/runSingleFileEmit.ts +139 -99
- package/src/compiler/internal/startResidentTransform.ts +9 -2
- package/src/compiler/internal/transformProjectInMemory.ts +12 -3
- package/src/compiler/internal/transformProjectInWorker.ts +10 -2
- package/src/internal/workerModuleUrl.ts +34 -0
- package/src/launcher/internal/buildSingleRootProject.ts +2 -0
- package/src/launcher/internal/getCompilerVersionText.ts +3 -2
- package/src/launcher/internal/prepareExecution.ts +2 -0
- package/src/launcher/internal/runTtsc.ts +123 -45
- package/src/launcher/internal/runtime/CommonJsRuntimeSource.ts +11 -9
- package/src/launcher/internal/runtime/advertiseTypeScriptExtensions.ts +25 -0
- package/src/launcher/internal/runtime/installRuntimeHooks.ts +7 -3
- package/src/launcher/internal/watch/AsyncWatchTopology.ts +267 -0
- package/src/launcher/internal/watch/WatchSettlement.ts +67 -0
- package/src/launcher/internal/watch/WatchTopology.ts +84 -13
- package/src/launcher/internal/watch/WatchTopologyWorkerProtocol.ts +106 -0
- package/src/launcher/internal/watch/serveWatchTopologyWorker.ts +75 -0
- package/src/launcher/internal/watch/watchTopologyWorker.ts +29 -0
- package/src/plugin/CapabilityPluginResolver.ts +9 -2
- package/src/plugin/internal/load/PluginDescriptorEvaluationCache.ts +17 -12
- package/src/plugin/internal/load/PluginPackageResolution.ts +14 -9
- package/src/plugin/internal/load/ProjectPluginEntries.ts +40 -15
- package/src/plugin/internal/load/collectProjectHostInputs.ts +7 -1
- package/src/plugin/internal/load/hasProjectPluginEntries.ts +8 -3
- package/src/plugin/internal/load/loadProjectPlugins.ts +672 -594
- package/src/plugin/internal/load/pluginResolutionFailure.ts +37 -0
- package/src/plugin/internal/source/PluginBuildEnvironmentReadings.ts +8 -2
- package/src/structures/ITtscCompilerContext.ts +12 -12
- package/src/structures/ITtscPlugin.ts +7 -5
- package/src/structures/ITtscPluginFactoryContext.ts +9 -8
- package/src/structures/internal/TtscSingleFileEmitOptions.ts +22 -11
|
@@ -35,8 +35,9 @@ import { resolveCacheDir } from "./resolveCacheDir";
|
|
|
35
35
|
import { resolveSingleFileOutput } from "./resolveSingleFileOutput";
|
|
36
36
|
import { resolveRuntimeCleanTargets } from "./runtime/resolveRuntimeCleanTargets";
|
|
37
37
|
import { withRuntimeDirectoryLock } from "./runtime/withRuntimeDirectoryLock";
|
|
38
|
+
import { AsyncWatchTopology } from "./watch/AsyncWatchTopology";
|
|
38
39
|
import { type WatchInputChange } from "./watch/WatchInputChange";
|
|
39
|
-
import {
|
|
40
|
+
import { WatchSettlement } from "./watch/WatchSettlement";
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
43
|
* CLI entry point for `ttsc`. Dispatches argv to the appropriate lane (build,
|
|
@@ -582,12 +583,26 @@ function printCacheHelp(): void {
|
|
|
582
583
|
* full request retains cache, reporting and watch callbacks. Only the private
|
|
583
584
|
* helper writes the selected public file. Success presentation follows that
|
|
584
585
|
* completed copy and describes public emission, without private products or a
|
|
585
|
-
* fabricated transform-site count. Watch supplies quiet true itself.
|
|
586
|
+
* fabricated transform-site count. Watch supplies quiet true itself. The async
|
|
587
|
+
* watch executor awaits input publication before building; ordinary CLI calls
|
|
588
|
+
* keep their synchronous return contract and share output planning.
|
|
586
589
|
*/
|
|
587
590
|
function runSingleFile(
|
|
588
591
|
options: ReturnType<typeof parseTtscBuildArgs> &
|
|
589
592
|
Pick<TtscSingleFileEmitOptions, "onProjectInputs" | "onWatchInputs">,
|
|
590
|
-
): number
|
|
593
|
+
): number;
|
|
594
|
+
function runSingleFile(
|
|
595
|
+
options: ReturnType<typeof parseTtscBuildArgs> &
|
|
596
|
+
Pick<TtscSingleFileEmitOptions, "onProjectInputs" | "onWatchInputs">,
|
|
597
|
+
execute: typeof runSingleFileEmit.async,
|
|
598
|
+
): Promise<number>;
|
|
599
|
+
function runSingleFile(
|
|
600
|
+
options: ReturnType<typeof parseTtscBuildArgs> &
|
|
601
|
+
Pick<TtscSingleFileEmitOptions, "onProjectInputs" | "onWatchInputs">,
|
|
602
|
+
execute:
|
|
603
|
+
| typeof runSingleFileEmit
|
|
604
|
+
| typeof runSingleFileEmit.async = runSingleFileEmit,
|
|
605
|
+
): number | Promise<number> {
|
|
591
606
|
if (options.files.length !== 1) {
|
|
592
607
|
throw new Error(
|
|
593
608
|
"ttsc: single-file mode currently accepts exactly one input file",
|
|
@@ -610,20 +625,25 @@ function runSingleFile(
|
|
|
610
625
|
project,
|
|
611
626
|
)
|
|
612
627
|
: undefined;
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
628
|
+
const result = execute({ ...options, cwd, file, out }, selection);
|
|
629
|
+
const report = (): number => {
|
|
630
|
+
if (options.quiet === false) {
|
|
631
|
+
process.stdout.write(
|
|
632
|
+
`// ttsc: tsconfig=${project.path} cwd=${cwd} emit=${emit}\n`,
|
|
633
|
+
);
|
|
634
|
+
if (out !== undefined) {
|
|
635
|
+
process.stdout.write(`// ttsc: emitted=1 files\n`);
|
|
636
|
+
process.stdout.write(` + ${relativeToCwd(cwd, out) || out}\n`);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
618
639
|
if (out !== undefined) {
|
|
619
|
-
process.stdout.write(
|
|
620
|
-
|
|
640
|
+
process.stdout.write(
|
|
641
|
+
`${relativeToCwd(cwd, out) || path.basename(out)}\n`,
|
|
642
|
+
);
|
|
621
643
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
}
|
|
626
|
-
return 0;
|
|
644
|
+
return 0;
|
|
645
|
+
};
|
|
646
|
+
return typeof result === "string" ? report() : result.then(report);
|
|
627
647
|
}
|
|
628
648
|
|
|
629
649
|
function runWatch(
|
|
@@ -631,7 +651,7 @@ function runWatch(
|
|
|
631
651
|
checkOnly: boolean,
|
|
632
652
|
): number {
|
|
633
653
|
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
634
|
-
let topology:
|
|
654
|
+
let topology: AsyncWatchTopology | undefined;
|
|
635
655
|
const invocation = {
|
|
636
656
|
...(checkOnly ? { ...options, emit: false } : options),
|
|
637
657
|
cwd,
|
|
@@ -639,10 +659,10 @@ function runWatch(
|
|
|
639
659
|
inputs: readonly string[],
|
|
640
660
|
identities?: PluginContentIdentities.Store,
|
|
641
661
|
) => {
|
|
642
|
-
topology?.setExtraInputs(inputs, identities);
|
|
662
|
+
return topology?.setExtraInputs(inputs, identities);
|
|
643
663
|
},
|
|
644
664
|
onProjectInputs: (inputs: ITtscProjectInputSnapshot) => {
|
|
645
|
-
topology?.setProjectInputs(inputs);
|
|
665
|
+
return topology?.setProjectInputs(inputs);
|
|
646
666
|
},
|
|
647
667
|
quiet: true,
|
|
648
668
|
};
|
|
@@ -653,6 +673,8 @@ function runWatch(
|
|
|
653
673
|
let closing: Promise<void> | undefined;
|
|
654
674
|
let rerun = false;
|
|
655
675
|
let timer: NodeJS.Timeout | null = null;
|
|
676
|
+
const settlement = new WatchSettlement();
|
|
677
|
+
let completedBuilds = 0;
|
|
656
678
|
const resident =
|
|
657
679
|
invocation.files.length === 0 ? new ResidentCheckWatchSession() : undefined;
|
|
658
680
|
const pendingChanges = new PendingResidentCheckWatchChanges();
|
|
@@ -664,6 +686,7 @@ function runWatch(
|
|
|
664
686
|
const runOnce = async () => {
|
|
665
687
|
if (closed) return;
|
|
666
688
|
running = true;
|
|
689
|
+
settlement.changed();
|
|
667
690
|
const change = pendingChanges.take();
|
|
668
691
|
if (process.env.TTSC_WATCH_DEBUG_INPUTS)
|
|
669
692
|
debugWatchInputs(`cycle ${JSON.stringify(change)}`);
|
|
@@ -682,14 +705,14 @@ function runWatch(
|
|
|
682
705
|
// rebuild reports a clear failure and the watcher keeps running instead
|
|
683
706
|
// of crashing the process with an uncaught exception.
|
|
684
707
|
const status = await (invocation.files.length !== 0
|
|
685
|
-
?
|
|
708
|
+
? runSingleFile(invocation, runSingleFileEmit.async)
|
|
686
709
|
: (async () => {
|
|
687
710
|
const buildOptions = checkOnly
|
|
688
711
|
? { ...invocation, emit: false }
|
|
689
712
|
: invocation;
|
|
690
713
|
const result =
|
|
691
714
|
resident === undefined
|
|
692
|
-
? runBuild(buildOptions)
|
|
715
|
+
? await runBuild.async(buildOptions)
|
|
693
716
|
: await resident.run(buildOptions, change);
|
|
694
717
|
// Watch output is one ordered stream. The diagnostics a build
|
|
695
718
|
// produced and the "[ttsc] watch build …" marker that concludes
|
|
@@ -710,6 +733,7 @@ function runWatch(
|
|
|
710
733
|
process.stdout.write(
|
|
711
734
|
`[ttsc] ${status === 0 ? "watch build complete" : "watch build failed"}\n`,
|
|
712
735
|
);
|
|
736
|
+
++completedBuilds;
|
|
713
737
|
} catch (error) {
|
|
714
738
|
if (closed) return;
|
|
715
739
|
// Same ordered-stream rule as the build path: the failure text goes on
|
|
@@ -719,30 +743,33 @@ function runWatch(
|
|
|
719
743
|
lastStatus = lastStatus === 0 ? 2 : lastStatus;
|
|
720
744
|
completedBuild = true;
|
|
721
745
|
process.stdout.write(`[ttsc] watch build failed\n`);
|
|
746
|
+
++completedBuilds;
|
|
722
747
|
} finally {
|
|
723
|
-
running = false;
|
|
724
748
|
if (completed && !closed) {
|
|
725
749
|
try {
|
|
726
750
|
// A filesystem event can arrive after the build reports completion
|
|
727
|
-
// but before
|
|
751
|
+
// but before post-build reconciliation reaches its re-resolution.
|
|
728
752
|
// Notify for a membership change here as well, otherwise that new
|
|
729
753
|
// input is silently absorbed into the watch set without a rebuild.
|
|
730
|
-
topology?.refresh(true);
|
|
754
|
+
await topology?.refresh(true);
|
|
731
755
|
} catch (error) {
|
|
732
756
|
process.stderr.write(
|
|
733
757
|
`[ttsc] watch error on ${watchMessagePath(cwd, root)}: ${formatError(error)}\n`,
|
|
734
758
|
);
|
|
735
759
|
}
|
|
736
760
|
}
|
|
761
|
+
running = false;
|
|
737
762
|
}
|
|
738
763
|
if (rerun) {
|
|
739
764
|
rerun = false;
|
|
740
765
|
trigger();
|
|
741
766
|
}
|
|
767
|
+
settlement.changed();
|
|
742
768
|
};
|
|
743
769
|
const trigger = (change?: WatchInputChange, reload = false) => {
|
|
744
770
|
if (closed) return;
|
|
745
771
|
pendingChanges.push(change, reload);
|
|
772
|
+
settlement.changed();
|
|
746
773
|
if (running) {
|
|
747
774
|
rerun = true;
|
|
748
775
|
return;
|
|
@@ -758,33 +785,30 @@ function runWatch(
|
|
|
758
785
|
activeSelected: active !== undefined,
|
|
759
786
|
});
|
|
760
787
|
closed = true;
|
|
788
|
+
settlement.changed();
|
|
761
789
|
if (timer) clearTimeout(timer);
|
|
762
790
|
timer = null;
|
|
763
791
|
process.off("SIGINT", onInterrupt);
|
|
764
792
|
process.off("SIGTERM", onTerminate);
|
|
765
793
|
process.off("message", onMessage);
|
|
766
794
|
process.off("disconnect", onDisconnect);
|
|
767
|
-
|
|
768
|
-
try {
|
|
769
|
-
topology?.close();
|
|
770
|
-
} catch (error) {
|
|
771
|
-
topologyError = error;
|
|
772
|
-
}
|
|
795
|
+
const topologyClosing = topology?.close() ?? Promise.resolve();
|
|
773
796
|
const residentClosing = resident?.close() ?? Promise.resolve();
|
|
774
797
|
const activeClosing = active ?? Promise.resolve();
|
|
775
|
-
closing = Promise.allSettled([
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
798
|
+
closing = Promise.allSettled([
|
|
799
|
+
topologyClosing,
|
|
800
|
+
residentClosing,
|
|
801
|
+
activeClosing,
|
|
802
|
+
]).then((results) => {
|
|
803
|
+
const errors = results.flatMap((result) =>
|
|
804
|
+
result.status === "rejected" ? [result.reason] : [],
|
|
805
|
+
);
|
|
806
|
+
if (errors.length !== 0)
|
|
807
|
+
throw new AggregateError(
|
|
808
|
+
errors,
|
|
809
|
+
`ttsc: watch shutdown failed: ${errors.map(formatError).join("; ")}`,
|
|
779
810
|
);
|
|
780
|
-
|
|
781
|
-
if (errors.length !== 0)
|
|
782
|
-
throw new AggregateError(
|
|
783
|
-
errors,
|
|
784
|
-
`ttsc: watch shutdown failed: ${errors.map(formatError).join("; ")}`,
|
|
785
|
-
);
|
|
786
|
-
},
|
|
787
|
-
);
|
|
811
|
+
});
|
|
788
812
|
if (process.env.TTSC_E2E_TRACE) {
|
|
789
813
|
// Observe the original promises without substituting their settlements.
|
|
790
814
|
void residentClosing.then(
|
|
@@ -893,9 +917,48 @@ function runWatch(
|
|
|
893
917
|
const id = message.id;
|
|
894
918
|
E2ETrace.watchShutdown("ipc-stop-received", { stopId: id });
|
|
895
919
|
void finish(id);
|
|
920
|
+
} else if (
|
|
921
|
+
typeof message === "object" &&
|
|
922
|
+
message !== null &&
|
|
923
|
+
"type" in message &&
|
|
924
|
+
message.type === "ttsc.watch.settle" &&
|
|
925
|
+
"id" in message &&
|
|
926
|
+
typeof message.id === "string" &&
|
|
927
|
+
message.id.length !== 0
|
|
928
|
+
) {
|
|
929
|
+
const id = message.id;
|
|
930
|
+
// Build markers retain their exact text and one marker per cycle. IPC
|
|
931
|
+
// travels on another pipe, so its receipt carries the completed count:
|
|
932
|
+
// a caller must drain those stdout markers before using the boundary.
|
|
933
|
+
void settlement
|
|
934
|
+
.wait(
|
|
935
|
+
async () => {
|
|
936
|
+
await topology?.whenIdle();
|
|
937
|
+
if (closed) throw new Error("ttsc: watch closed before settling");
|
|
938
|
+
return !running && !rerun && timer === null;
|
|
939
|
+
},
|
|
940
|
+
async () => {
|
|
941
|
+
if (process.connected && process.send !== undefined)
|
|
942
|
+
await new Promise<void>((resolve, reject) => {
|
|
943
|
+
process.send!(
|
|
944
|
+
{ type: "ttsc.watch.settled", id, builds: completedBuilds },
|
|
945
|
+
(error: Error | null) =>
|
|
946
|
+
error === null ? resolve() : reject(error),
|
|
947
|
+
);
|
|
948
|
+
});
|
|
949
|
+
},
|
|
950
|
+
)
|
|
951
|
+
.catch((error: unknown) => {
|
|
952
|
+
if (!closed) {
|
|
953
|
+
process.stderr.write(`${formatError(error)}\n`);
|
|
954
|
+
lastStatus = lastStatus === 0 ? 2 : lastStatus;
|
|
955
|
+
void finish();
|
|
956
|
+
}
|
|
957
|
+
});
|
|
896
958
|
}
|
|
897
959
|
};
|
|
898
960
|
const startRun = () => {
|
|
961
|
+
timer = null;
|
|
899
962
|
active = runOnce();
|
|
900
963
|
void active.catch((error: unknown) => {
|
|
901
964
|
process.stderr.write(`${formatError(error)}\n`);
|
|
@@ -904,7 +967,13 @@ function runWatch(
|
|
|
904
967
|
});
|
|
905
968
|
};
|
|
906
969
|
|
|
907
|
-
topology = new
|
|
970
|
+
topology = new AsyncWatchTopology(invocation, {
|
|
971
|
+
onFailure: (error) => {
|
|
972
|
+
if (closed) return;
|
|
973
|
+
lastStatus = lastStatus === 0 ? 2 : lastStatus;
|
|
974
|
+
process.stderr.write(`${formatError(error)}\n`);
|
|
975
|
+
void finish();
|
|
976
|
+
},
|
|
908
977
|
onError: (location, error) => {
|
|
909
978
|
process.stderr.write(
|
|
910
979
|
`[ttsc] watch error on ${watchMessagePath(cwd, location)}: ${formatError(error)}\n`,
|
|
@@ -934,16 +1003,25 @@ function runWatch(
|
|
|
934
1003
|
},
|
|
935
1004
|
onTopologyChange: () => trigger(undefined, true),
|
|
936
1005
|
});
|
|
1006
|
+
const start = async (): Promise<void> => {
|
|
1007
|
+
await topology!.refresh(false);
|
|
1008
|
+
if (closed) return;
|
|
1009
|
+
process.stdout.write(`[ttsc] watching ${watchMessagePath(cwd, root)}\n`);
|
|
1010
|
+
startRun();
|
|
1011
|
+
};
|
|
937
1012
|
try {
|
|
938
|
-
topology.refresh(false);
|
|
939
1013
|
process.on("SIGINT", onInterrupt);
|
|
940
1014
|
process.on("SIGTERM", onTerminate);
|
|
941
1015
|
if (process.connected) {
|
|
942
1016
|
process.on("message", onMessage);
|
|
943
1017
|
process.on("disconnect", onDisconnect);
|
|
944
1018
|
}
|
|
945
|
-
|
|
946
|
-
|
|
1019
|
+
void start().catch((error: unknown) => {
|
|
1020
|
+
if (closed) return;
|
|
1021
|
+
lastStatus = lastStatus === 0 ? 2 : lastStatus;
|
|
1022
|
+
process.stderr.write(`${formatError(error)}\n`);
|
|
1023
|
+
void finish();
|
|
1024
|
+
});
|
|
947
1025
|
} catch (error) {
|
|
948
1026
|
// Refresh may fail after acquiring only part of the watch set. Release that
|
|
949
1027
|
// partial ownership as well as setup's signal listeners before returning.
|
|
@@ -71,16 +71,20 @@ export namespace CommonJsRuntimeSource {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
* Construct an owned require
|
|
74
|
+
* Construct an owned require sharing the original live extension registry.
|
|
75
75
|
*
|
|
76
|
-
*
|
|
76
|
+
* Node's loader and every native require share this registration object.
|
|
77
|
+
* Copying it hides later registrations, replacements and deletions from one
|
|
78
|
+
* side; source-extension advertisement belongs to runtime installation.
|
|
79
|
+
*
|
|
80
|
+
* @evidence contracts/common.md#principled-implementation createRequire loads through Node's shared CommonJS cache; copied public properties preserve cache/main access, and the original registry reference preserves the public extension-registration contract across later edits. Missing original metadata falls back to the native registry.
|
|
77
81
|
* @evidence contracts/common.md#clear-and-simple-design The callable and resolve member share one filename anchor; source recovery remains in the configured policy.
|
|
78
|
-
* @evidence contracts/common.md#prohibited-implementation-shortcuts
|
|
79
|
-
* @evidence contracts/common.md#meaningful-documentation Native prose
|
|
82
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Construction assigns only the owned function's properties, adds no extension capability and replaces no foreign handler or private loader slot. Runtime installation separately advertises its supported CommonJS source extensions.
|
|
83
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose explains why live registry identity is required and assigns advertisement to the installation owner.
|
|
80
84
|
* @evidence contracts/portability.md#os-neutral-implementation The public createRequire API takes the native filename; no OS-name or path-string case heuristic is introduced.
|
|
81
|
-
* @evidence contracts/performance.md#efficient-algorithms Construction copies public require properties and
|
|
85
|
+
* @evidence contracts/performance.md#efficient-algorithms Construction copies P public require properties and creates a native filename-anchored require without traversing or allocating another extension registry. Calls delegate native resolution, module evaluation/cache work or the configured resolver; their cost is not bounded by property count.
|
|
82
86
|
* @evidence contracts/performance.md#reuse-equivalent-work Callable loading delegates to Node's CommonJS cache; the configured resolve policy remains a distinct per-call operation, not a cached result of constructing the function.
|
|
83
|
-
* @evidence contracts/performance.md#bound-retention-and-release-resources The evaluated module owns the returned function
|
|
87
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources The evaluated module owns the returned function and captured filename/native require. Cache, main and extension-registry references share Node or original-require state; the factory adds no registry copy, historical module collection or native handle.
|
|
84
88
|
*/
|
|
85
89
|
export function create(
|
|
86
90
|
original: NodeJS.Require,
|
|
@@ -107,9 +111,7 @@ export namespace CommonJsRuntimeSource {
|
|
|
107
111
|
)) as NodeJS.RequireResolve;
|
|
108
112
|
owned.resolve.paths = native.resolve.paths;
|
|
109
113
|
owned.cache = original.cache ?? native.cache;
|
|
110
|
-
owned.extensions =
|
|
111
|
-
for (const extension of [".ts", ".tsx", ".cts", ".mts"])
|
|
112
|
-
owned.extensions[extension] = owned.extensions[".js"]!;
|
|
114
|
+
owned.extensions = original.extensions ?? native.extensions;
|
|
113
115
|
return owned;
|
|
114
116
|
}
|
|
115
117
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Publish the CommonJS source extensions served by the installed runtime hooks.
|
|
3
|
+
*
|
|
4
|
+
* Tools such as tsconfig-paths enumerate the process registry before asking
|
|
5
|
+
* Node to resolve a file, and rechoir checks it before loading a typed config.
|
|
6
|
+
* A module-local copy cannot satisfy those checks. Add only missing entries
|
|
7
|
+
* using Node's JavaScript handler; registerHooks still owns source compilation
|
|
8
|
+
* and existing loader handlers keep their identity. Node probes these entries
|
|
9
|
+
* after its existing extensions, preserving JavaScript precedence.
|
|
10
|
+
*
|
|
11
|
+
* @evidence contracts/common.md#principled-implementation The public require.extensions registry advertises supported CommonJS source loading to consumers that inspect extensions before resolution; absent entries delegate to Node's existing JavaScript handler, which consumes the source supplied by registerHooks.
|
|
12
|
+
* @evidence contracts/common.md#clear-and-simple-design One installation operation publishes loader capability without adding a second compilation or resolution path.
|
|
13
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Only missing public registry entries are added; no foreign handler or method is replaced and no consumer identity affects production behavior. The source suffixes describe the supported CommonJS contract rather than fixture-specific routes.
|
|
14
|
+
* @evidence contracts/common.md#meaningful-documentation The prose explains why process-wide advertisement is needed, who compiles the source, which handlers remain authoritative and how native precedence is preserved.
|
|
15
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Registry updates use JavaScript property semantics without filesystem, path or process arguments; Node's loader owns native resolution.
|
|
16
|
+
* @evidence contracts/performance.md#efficient-algorithms A fixed set of three CommonJS source extensions requires constant time and space, without scanning modules or files.
|
|
17
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work This capability publication shares no computed compilation or resolution result.
|
|
18
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources The caller's process registry retains at most three added references to an existing Node handler for the installed hooks' process lifetime; no handle or task is acquired.
|
|
19
|
+
*/
|
|
20
|
+
export function advertiseTypeScriptExtensions(
|
|
21
|
+
extensions: NodeJS.RequireExtensions,
|
|
22
|
+
): void {
|
|
23
|
+
for (const extension of [".ts", ".tsx", ".cts"])
|
|
24
|
+
extensions[extension] ??= extensions[".js"]!;
|
|
25
|
+
}
|
|
@@ -43,6 +43,7 @@ import type { RuntimeManifest } from "./RuntimeManifest";
|
|
|
43
43
|
import { RuntimeManifestRegistry } from "./RuntimeManifestRegistry";
|
|
44
44
|
import { RuntimeModuleFormat } from "./RuntimeModuleFormat";
|
|
45
45
|
import { RuntimeProjectOwnership } from "./RuntimeProjectOwnership";
|
|
46
|
+
import { advertiseTypeScriptExtensions } from "./advertiseTypeScriptExtensions";
|
|
46
47
|
import { checkNodeRuntimeSupport } from "./checkNodeRuntimeSupport";
|
|
47
48
|
import { commonJsExportNames } from "./commonJsExportNames";
|
|
48
49
|
import { commonJsImportFacade } from "./commonJsImportFacade";
|
|
@@ -94,8 +95,10 @@ import { selectRuntimePluginPolicy } from "./selectRuntimePluginPolicy";
|
|
|
94
95
|
* reach the API lacks on some releases is `require.resolve`, which is probed
|
|
95
96
|
* before installation. Served CommonJS bodies receive an owned require function
|
|
96
97
|
* whose resolve member applies the same source policy on those releases. Its
|
|
97
|
-
*
|
|
98
|
-
*
|
|
98
|
+
* shared extension registry preserves live registrations. Installation also
|
|
99
|
+
* advertises missing CommonJS source extensions in the process registry because
|
|
100
|
+
* ecosystem tools inspect it before resolution; existing handlers remain intact
|
|
101
|
+
* and foreign resolver methods are never replaced.
|
|
99
102
|
*
|
|
100
103
|
* Direct descriptor evaluation records user preloads after hook installation.
|
|
101
104
|
* Only the generated CommonJS output sibling takes Node's native resolve/load
|
|
@@ -104,7 +107,7 @@ import { selectRuntimePluginPolicy } from "./selectRuntimePluginPolicy";
|
|
|
104
107
|
*
|
|
105
108
|
* @evidence contracts/common.md#principled-implementation Resolution preserves successful Node decisions, rescues source spellings only after documented resolution fails, and serves only outputs whose ownership index names the exact source. CommonJS facades delegate native evaluation and project detected own named exports under the selected namespace capability; an owned module-local require supplies source resolution when native require.resolve bypasses public hooks.
|
|
106
109
|
* @evidence contracts/common.md#clear-and-simple-design One synchronous hook owner coordinates source selection, emission ownership and descriptor observation; the entry, owning-project and orphan lanes remain explicit because they have distinct compilation premises. Private helpers carry those policies without a second foreign-resolver layer.
|
|
107
|
-
* @evidence contracts/common.md#prohibited-implementation-shortcuts Public registerHooks handles resolution and loading; installation
|
|
110
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Public registerHooks handles resolution and loading; installation adds missing public extension entries with Node's own JavaScript handler while preserving every existing handler and resolver method. Source-extension recovery implements emitted-to-source spelling under the runtime contract, and module-local require adaptation addresses the probed public-hook difference without replacing Node methods.
|
|
108
111
|
* @evidence contracts/common.md#meaningful-documentation Native paragraphs describe the three serving lanes, compile gates, source identity, capability-based local adaptation and extension-registry ownership; helper comments state ownership and failure effects with descriptive prose separated from tags.
|
|
109
112
|
* @evidence contracts/portability.md#os-neutral-implementation Node URL conversion, native filesystem paths and physical resolution preserve OS spelling boundaries. Actual public-hook probes select runtime capabilities, native emit uses executable arguments without shell interpolation, and unresolved filesystem observation refuses reusable descriptor proof.
|
|
110
113
|
* @evidence contracts/performance.md#efficient-algorithms Source ownership indexes replace repeated whole-emit scans with indexed source/native-identity queries. Export discovery processes source/emit bytes, reexport edges, native resolution and Set/name unions under traversal-local seen sets; separate roots can repeat traversal. Config-chain validation reads discovered inputs. Compiler identity brackets and streams executable bytes on valid lookups, refusing failed observations. Native build/name-scan/orphan paths add compilation, path/metadata/IO cost; recursive graphs remain subject to stack limits.
|
|
@@ -134,6 +137,7 @@ export function installRuntimeHooks(options: RuntimeHookOptions = {}): void {
|
|
|
134
137
|
process.setSourceMapsEnabled(true);
|
|
135
138
|
}
|
|
136
139
|
registerHooks({ load, resolve });
|
|
140
|
+
advertiseTypeScriptExtensions(require.extensions);
|
|
137
141
|
PluginDescriptorInputObservation.begin(true);
|
|
138
142
|
installed = true;
|
|
139
143
|
}
|