ttsc 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cmd/graphbench/main.go +26 -16
- package/cmd/graphdump/main.go +37 -12
- package/cmd/graphdump/run_declares_the_capability_its_output_carries_test.go +137 -0
- package/cmd/graphdump/run_reports_an_unknown_flag_without_exiting_the_process_test.go +56 -0
- package/cmd/graphdump/run_reports_an_unloadable_project_without_printing_a_dump_test.go +46 -0
- package/cmd/ttsc/api_transform.go +17 -6
- package/cmd/ttscgraph/dump.go +43 -11
- package/cmd/ttscgraph/run_dump_claims_artifacts_only_when_it_asked_test.go +135 -0
- package/cmd/ttscgraph/run_dump_declares_the_capability_its_output_carries_test.go +96 -0
- package/cmd/ttscgraph/serve.go +253 -25
- package/cmd/ttscgraph/serve_adopts_a_republished_artifact_set_test.go +348 -0
- package/cmd/ttscgraph/serve_projects_an_artifact_no_source_owns_test.go +90 -0
- package/cmd/ttscgraph/serve_shards.go +31 -9
- package/driver/config_discovery.go +121 -0
- package/driver/emit_plugin.go +57 -8
- package/driver/plugins.go +125 -14
- package/driver/transform_dependencies.go +283 -0
- package/driver/transform_dependencies_declares_every_file_without_a_contributor_test.go +28 -0
- package/driver/transform_dependencies_drops_a_self_reported_dependency_test.go +21 -0
- package/driver/transform_dependencies_keys_a_reported_path_like_the_envelope_test.go +46 -0
- package/driver/transform_dependencies_requires_every_contributor_to_declare_test.go +38 -0
- package/driver/transform_dependencies_stays_silent_for_an_undeclared_contributor_test.go +23 -0
- package/driver/transform_dependencies_withdraws_completeness_after_an_unusable_dependency_test.go +37 -0
- package/internal/graph/artifacts.go +230 -0
- package/internal/graph/artifacts_index_what_a_plugin_published_test.go +154 -0
- package/internal/graph/artifacts_survive_a_partial_rebuild_test.go +89 -0
- package/internal/graph/build.go +35 -0
- package/internal/graph/build_releases_the_scratch_it_no_longer_reads_test.go +118 -0
- package/internal/graph/doc_refs_are_the_use_the_checker_already_counts_test.go +93 -0
- package/internal/graph/doc_refs_resolve_documentation_links_test.go +335 -0
- package/internal/graph/doc_tags.go +416 -0
- package/internal/graph/doc_tags_are_claimed_before_they_are_read_test.go +131 -0
- package/internal/graph/doc_tags_capture_every_unrecognized_tag_test.go +165 -0
- package/internal/graph/doc_tags_read_only_what_the_parser_attached_test.go +97 -0
- package/internal/graph/doc_tags_stop_at_the_external_boundary_test.go +59 -0
- package/internal/graph/doc_tags_survive_line_endings_and_repeated_blocks_test.go +146 -0
- package/internal/graph/dump.go +60 -13
- package/internal/graph/dump_checkout_paths_are_stable_test.go +2 -2
- package/internal/graph/dump_paths.go +2 -2
- package/internal/graph/dump_paths_are_portable_and_injective_test.go +1 -1
- package/internal/graph/edge_kinds_names_every_declared_kind_test.go +49 -0
- package/internal/graph/edges.go +1 -0
- package/internal/graph/graph.go +79 -4
- package/internal/graph/provenance.go +29 -2
- package/lib/compiler/internal/project/createNativeProjectContextArgs.d.ts +9 -0
- package/lib/compiler/internal/project/createNativeProjectContextArgs.js +16 -4
- package/lib/compiler/internal/project/createNativeProjectContextArgs.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/launcher/internal/runtimeHooks.d.ts +10 -2
- package/lib/launcher/internal/runtimeHooks.js +93 -2
- package/lib/launcher/internal/runtimeHooks.js.map +1 -1
- package/lib/plugin/internal/capabilityResolutionCache.d.ts +76 -0
- package/lib/plugin/internal/capabilityResolutionCache.js +224 -0
- package/lib/plugin/internal/capabilityResolutionCache.js.map +1 -0
- package/lib/plugin/resolveCapabilityPlugins.d.ts +55 -0
- package/lib/plugin/resolveCapabilityPlugins.js +118 -0
- package/lib/plugin/resolveCapabilityPlugins.js.map +1 -0
- package/lib/structures/ITtscCompilerTransformation.d.ts +7 -0
- package/package.json +8 -8
- package/shim/ast/parent.go +16 -3
- package/shim/checker/enums_gen.go +11 -0
- package/shim/checker/shim.go +3 -0
- package/shim/compiler/emithook.go +10 -0
- package/src/compiler/internal/project/createNativeProjectContextArgs.ts +19 -4
- package/src/index.ts +1 -0
- package/src/launcher/internal/runtimeHooks.ts +111 -2
- package/src/plugin/internal/capabilityResolutionCache.ts +305 -0
- package/src/plugin/resolveCapabilityPlugins.ts +171 -0
- package/src/structures/ITtscCompilerTransformation.ts +7 -0
- package/tools/shim_audit/baseline.json +0 -1
- package/utility/host.go +15 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilityResolutionCache.js","sourceRoot":"","sources":["../../../src/plugin/internal/capabilityResolutionCache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One plugin that declared the requested capability.
|
|
3
|
+
*
|
|
4
|
+
* `manifest` is the `--plugins-json` payload its sidecar needs to find its own
|
|
5
|
+
* configured entry. Without it the sidecar loads an empty rule configuration
|
|
6
|
+
* and answers as though the project declared nothing — an empty answer that
|
|
7
|
+
* looks exactly like a project which genuinely publishes none.
|
|
8
|
+
*/
|
|
9
|
+
export interface ITtscCapabilityPlugin {
|
|
10
|
+
binary: string;
|
|
11
|
+
manifest: string;
|
|
12
|
+
/**
|
|
13
|
+
* The `--project-context-json` payload, or `undefined` when the plugin's
|
|
14
|
+
* descriptor does not declare it wants one.
|
|
15
|
+
*
|
|
16
|
+
* A sidecar is handed a project root, not asked to derive one. Without this a
|
|
17
|
+
* rule that resolves its own inputs — the documents an evidence claim reads,
|
|
18
|
+
* a Prisma schema, an OpenAPI file — has no base to resolve them against, and
|
|
19
|
+
* answers with an empty set rather than an error, because "this project
|
|
20
|
+
* declares nothing" is a legitimate answer it cannot distinguish from "I was
|
|
21
|
+
* not told where the project is".
|
|
22
|
+
*/
|
|
23
|
+
projectContext?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The built sidecars of a project's configured plugins that declare one
|
|
27
|
+
* capability.
|
|
28
|
+
*
|
|
29
|
+
* This is the seam a consumer outside the compiler needs to ask a plugin a
|
|
30
|
+
* question the plugin declared it can answer. `ttscserver` already does this
|
|
31
|
+
* for `capabilities.lsp`, but it does it from inside the launcher; a separate
|
|
32
|
+
* tool — `@ttsc/graph`, an editor integration, a script — had no way to reach
|
|
33
|
+
* the same answer without reimplementing plugin discovery, descriptor
|
|
34
|
+
* evaluation, and the Go source build cache.
|
|
35
|
+
*
|
|
36
|
+
* It is contributor-agnostic by construction: the caller names a capability,
|
|
37
|
+
* not a package. A project that configures no plugin, or none declaring that
|
|
38
|
+
* capability, gets an empty array — which is an answer, not a failure, and is
|
|
39
|
+
* the common case.
|
|
40
|
+
*
|
|
41
|
+
* Building a plugin is not free the first time. The Go source build is cached
|
|
42
|
+
* by content, so a warm project pays a lookup; a cold one pays the build the
|
|
43
|
+
* next `ttsc` invocation would have paid anyway.
|
|
44
|
+
*
|
|
45
|
+
* @param options.capability - Capability flag the plugin descriptor must
|
|
46
|
+
* declare.
|
|
47
|
+
* @param options.cwd - Project root. Defaults to the current directory.
|
|
48
|
+
* @param options.tsconfig - Project tsconfig path, relative to `cwd`.
|
|
49
|
+
* @returns One entry per declaring plugin, in configured plugin order.
|
|
50
|
+
*/
|
|
51
|
+
export declare function resolveCapabilityPlugins(options: {
|
|
52
|
+
capability: string;
|
|
53
|
+
cwd?: string;
|
|
54
|
+
tsconfig?: string;
|
|
55
|
+
}): ITtscCapabilityPlugin[];
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolveCapabilityPlugins = resolveCapabilityPlugins;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const createNativeProjectContextArgs_1 = require("../compiler/internal/project/createNativeProjectContextArgs");
|
|
10
|
+
const resolveBinary_1 = require("../compiler/internal/resolveBinary");
|
|
11
|
+
const capabilityResolutionCache_1 = require("./internal/capabilityResolutionCache");
|
|
12
|
+
const loadProjectPlugins_1 = require("./internal/loadProjectPlugins");
|
|
13
|
+
/**
|
|
14
|
+
* The built sidecars of a project's configured plugins that declare one
|
|
15
|
+
* capability.
|
|
16
|
+
*
|
|
17
|
+
* This is the seam a consumer outside the compiler needs to ask a plugin a
|
|
18
|
+
* question the plugin declared it can answer. `ttscserver` already does this
|
|
19
|
+
* for `capabilities.lsp`, but it does it from inside the launcher; a separate
|
|
20
|
+
* tool — `@ttsc/graph`, an editor integration, a script — had no way to reach
|
|
21
|
+
* the same answer without reimplementing plugin discovery, descriptor
|
|
22
|
+
* evaluation, and the Go source build cache.
|
|
23
|
+
*
|
|
24
|
+
* It is contributor-agnostic by construction: the caller names a capability,
|
|
25
|
+
* not a package. A project that configures no plugin, or none declaring that
|
|
26
|
+
* capability, gets an empty array — which is an answer, not a failure, and is
|
|
27
|
+
* the common case.
|
|
28
|
+
*
|
|
29
|
+
* Building a plugin is not free the first time. The Go source build is cached
|
|
30
|
+
* by content, so a warm project pays a lookup; a cold one pays the build the
|
|
31
|
+
* next `ttsc` invocation would have paid anyway.
|
|
32
|
+
*
|
|
33
|
+
* @param options.capability - Capability flag the plugin descriptor must
|
|
34
|
+
* declare.
|
|
35
|
+
* @param options.cwd - Project root. Defaults to the current directory.
|
|
36
|
+
* @param options.tsconfig - Project tsconfig path, relative to `cwd`.
|
|
37
|
+
* @returns One entry per declaring plugin, in configured plugin order.
|
|
38
|
+
*/
|
|
39
|
+
function resolveCapabilityPlugins(options) {
|
|
40
|
+
const cwd = node_path_1.default.resolve(options.cwd ?? process.cwd());
|
|
41
|
+
const tsconfig = options.tsconfig ?? "tsconfig.json";
|
|
42
|
+
const cached = (0, capabilityResolutionCache_1.readCapabilityResolution)({ cwd, tsconfig, version });
|
|
43
|
+
if (cached !== null)
|
|
44
|
+
return select(cached, options.capability);
|
|
45
|
+
const binary = (0, resolveBinary_1.resolveBinary)();
|
|
46
|
+
if (binary === null || binary === undefined)
|
|
47
|
+
return [];
|
|
48
|
+
try {
|
|
49
|
+
const loaded = (0, loadProjectPlugins_1.loadProjectPlugins)({
|
|
50
|
+
binary,
|
|
51
|
+
cwd: options.cwd,
|
|
52
|
+
tsconfig: options.tsconfig,
|
|
53
|
+
});
|
|
54
|
+
// The manifest carries every configured plugin, not only the declaring one.
|
|
55
|
+
// A sidecar reads its OWN entry out of it — that entry is where its config
|
|
56
|
+
// file lives — and a manifest narrowed to the caller's capability would hand
|
|
57
|
+
// it a project it does not recognize, which is an empty answer rather than an
|
|
58
|
+
// error. This is the same string `runBuild` passes for a check-stage plugin.
|
|
59
|
+
const manifest = JSON.stringify(loaded.nativePlugins.map((plugin) => ({
|
|
60
|
+
config: plugin.config,
|
|
61
|
+
name: plugin.name,
|
|
62
|
+
stage: plugin.stage,
|
|
63
|
+
})));
|
|
64
|
+
const wantsContext = loaded.nativePlugins.some((plugin) => plugin.capabilities
|
|
65
|
+
?.projectContextArgs === true);
|
|
66
|
+
const answer = {
|
|
67
|
+
hostInputs: loaded.hostInputs,
|
|
68
|
+
manifest,
|
|
69
|
+
plugins: loaded.nativePlugins.map((plugin) => ({
|
|
70
|
+
binary: plugin.binary,
|
|
71
|
+
capabilities: Object.fromEntries(Object.entries(plugin.capabilities ?? {}).map(([name, declared]) => [name, declared === true])),
|
|
72
|
+
source: plugin.source,
|
|
73
|
+
})),
|
|
74
|
+
projectContext: wantsContext
|
|
75
|
+
? (0, createNativeProjectContextArgs_1.createNativeProjectContextJson)(loaded.project)
|
|
76
|
+
: null,
|
|
77
|
+
};
|
|
78
|
+
(0, capabilityResolutionCache_1.writeCapabilityResolution)({ cwd, tsconfig, version }, answer);
|
|
79
|
+
return select(answer, options.capability);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// A project whose plugin configuration does not load is a project the user
|
|
83
|
+
// already sees an error for, from the command that compiles it. Failing here
|
|
84
|
+
// would turn "your lint config has a typo" into "the graph is broken", and
|
|
85
|
+
// the caller's own degraded answer is the honest one.
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** The declaring plugins, from a resolution however it was obtained. */
|
|
90
|
+
function select(resolution, capability) {
|
|
91
|
+
return resolution.plugins
|
|
92
|
+
.filter((plugin) => plugin.binary !== "" && plugin.capabilities[capability] === true)
|
|
93
|
+
.map((plugin) => ({
|
|
94
|
+
binary: plugin.binary,
|
|
95
|
+
manifest: resolution.manifest,
|
|
96
|
+
...(plugin.capabilities.projectContextArgs === true &&
|
|
97
|
+
resolution.projectContext !== null
|
|
98
|
+
? { projectContext: resolution.projectContext }
|
|
99
|
+
: {}),
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* This build, as the resolution cache's key material.
|
|
104
|
+
*
|
|
105
|
+
* A ttsc upgrade can change what discovery finds — a new descriptor field, a
|
|
106
|
+
* different resolution order — so an entry written by another build is not this
|
|
107
|
+
* build's answer.
|
|
108
|
+
*/
|
|
109
|
+
const version = (() => {
|
|
110
|
+
try {
|
|
111
|
+
const manifest = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.resolve(__dirname, "..", "..", "package.json"), "utf8"));
|
|
112
|
+
return typeof manifest.version === "string" ? manifest.version : "0.0.0";
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return "0.0.0";
|
|
116
|
+
}
|
|
117
|
+
})();
|
|
118
|
+
//# sourceMappingURL=resolveCapabilityPlugins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveCapabilityPlugins.js","sourceRoot":"","sources":["../../src/plugin/resolveCapabilityPlugins.ts"],"names":[],"mappings":"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"}
|
|
@@ -118,6 +118,13 @@ export declare namespace ITtscCompilerTransformation {
|
|
|
118
118
|
* declares completeness should stamp {@link graph} too; without it a listed
|
|
119
119
|
* file retains no universal input at all.
|
|
120
120
|
*
|
|
121
|
+
* Ttsc's own hosts stamp it for what they can prove: their source-to-source
|
|
122
|
+
* output is a syntactic re-print, so the built-in native host and the
|
|
123
|
+
* linked-plugin host list a file once every linked plugin able to
|
|
124
|
+
* contribute to it has declared its own contribution complete — which,
|
|
125
|
+
* where no plugin is active at all, is every file. An executable sidecar
|
|
126
|
+
* prints its own envelope and decides for itself.
|
|
127
|
+
*
|
|
121
128
|
* Optional, and never required for correctness: an envelope without this
|
|
122
129
|
* field keeps the sound host-owned bound. A file that is both listed here
|
|
123
130
|
* and in {@link volatile} keeps the union, since the two claims contradict
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ttsc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "General-purpose TypeScript-Go compiler, runtime, plugin host, and LSP host.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -43,13 +43,13 @@
|
|
|
43
43
|
"typescript": "^7.0.2"
|
|
44
44
|
},
|
|
45
45
|
"optionalDependencies": {
|
|
46
|
-
"@ttsc/linux-
|
|
47
|
-
"@ttsc/
|
|
48
|
-
"@ttsc/
|
|
49
|
-
"@ttsc/
|
|
50
|
-
"@ttsc/
|
|
51
|
-
"@ttsc/
|
|
52
|
-
"@ttsc/
|
|
46
|
+
"@ttsc/linux-arm": "0.28.0",
|
|
47
|
+
"@ttsc/darwin-x64": "0.28.0",
|
|
48
|
+
"@ttsc/linux-x64": "0.28.0",
|
|
49
|
+
"@ttsc/win32-x64": "0.28.0",
|
|
50
|
+
"@ttsc/win32-arm64": "0.28.0",
|
|
51
|
+
"@ttsc/darwin-arm64": "0.28.0",
|
|
52
|
+
"@ttsc/linux-arm64": "0.28.0"
|
|
53
53
|
},
|
|
54
54
|
"sideEffects": [
|
|
55
55
|
"./lib/register.js",
|
package/shim/ast/parent.go
CHANGED
|
@@ -6,9 +6,17 @@ import innerast "github.com/microsoft/typescript-go/internal/ast"
|
|
|
6
6
|
// its containing node.
|
|
7
7
|
//
|
|
8
8
|
// A transform that splices freshly built (synthetic) nodes onto a SourceFile
|
|
9
|
-
// must call this before emit
|
|
10
|
-
//
|
|
11
|
-
//
|
|
9
|
+
// must call this before emit, because the passes that then walk the spliced tree
|
|
10
|
+
// dereference Parent and would hit nil on a synthetic node. The printer is the
|
|
11
|
+
// example that holds up: getContainingNodeArray reads node.Parent unguarded for
|
|
12
|
+
// a parameter, template span, decorator, and heritage clause.
|
|
13
|
+
//
|
|
14
|
+
// Two earlier examples were dropped rather than the rule. The emit resolver's
|
|
15
|
+
// reference marking no longer walks the spliced tree at all in ttsc's plugin
|
|
16
|
+
// emit lane, which builds the builtin chain from the parse tree (see
|
|
17
|
+
// driver.EmitWithPluginTransformers). The module transform's own Parent reads
|
|
18
|
+
// carry upstream //nolint:customlint notes saying they deliberately inspect
|
|
19
|
+
// parse-tree parents.
|
|
12
20
|
func SetParentInChildren(node *Node) {
|
|
13
21
|
innerast.SetParentInChildren(node)
|
|
14
22
|
}
|
|
@@ -20,6 +28,11 @@ func SetParentInChildren(node *Node) {
|
|
|
20
28
|
// kept verbatim while sibling statements were rewritten) makes tsgo's
|
|
21
29
|
// runtime-syntax/printer mis-resolve the declaration and drop it from emit.
|
|
22
30
|
// Only freshly built (synthetic) nodes need a parent wired, and those start nil.
|
|
31
|
+
//
|
|
32
|
+
// This is the form ttsc's plugin emit lane calls. How much it currently carries
|
|
33
|
+
// is unproven: stubbing the call out leaves the whole driver suite green, which
|
|
34
|
+
// measures the suite's coverage of parent-dependent emit rather than the hazard.
|
|
35
|
+
// Keep it for the reason above, not on the strength of a failing test.
|
|
23
36
|
func SetParentInChildrenUnset(node *Node) {
|
|
24
37
|
node.ForEachChild(func(child *Node) bool {
|
|
25
38
|
if child.Parent == nil {
|
|
@@ -77,6 +77,17 @@ const (
|
|
|
77
77
|
ObjectFlagsSingleSignatureType = innerchecker.ObjectFlagsSingleSignatureType
|
|
78
78
|
ObjectFlagsTuple = innerchecker.ObjectFlagsTuple
|
|
79
79
|
ObjectFlagsUnresolvedMembers = innerchecker.ObjectFlagsUnresolvedMembers
|
|
80
|
+
SignatureFlagsCallChainFlags = innerchecker.SignatureFlagsCallChainFlags
|
|
81
|
+
SignatureFlagsConstruct = innerchecker.SignatureFlagsConstruct
|
|
82
|
+
SignatureFlagsHasLiteralTypes = innerchecker.SignatureFlagsHasLiteralTypes
|
|
83
|
+
SignatureFlagsHasRestParameter = innerchecker.SignatureFlagsHasRestParameter
|
|
84
|
+
SignatureFlagsIsInnerCallChain = innerchecker.SignatureFlagsIsInnerCallChain
|
|
85
|
+
SignatureFlagsIsNonInferrable = innerchecker.SignatureFlagsIsNonInferrable
|
|
86
|
+
SignatureFlagsIsOuterCallChain = innerchecker.SignatureFlagsIsOuterCallChain
|
|
87
|
+
SignatureFlagsIsSignatureCandidateForOverloadFailure = innerchecker.SignatureFlagsIsSignatureCandidateForOverloadFailure
|
|
88
|
+
SignatureFlagsIsUntypedSignatureInJSFile = innerchecker.SignatureFlagsIsUntypedSignatureInJSFile
|
|
89
|
+
SignatureFlagsNone = innerchecker.SignatureFlagsNone
|
|
90
|
+
SignatureFlagsPropagatingFlags = innerchecker.SignatureFlagsPropagatingFlags
|
|
80
91
|
SignatureKindConstruct = innerchecker.SignatureKindConstruct
|
|
81
92
|
TypeFlagsAnyOrUnknown = innerchecker.TypeFlagsAnyOrUnknown
|
|
82
93
|
TypeFlagsBigInt = innerchecker.TypeFlagsBigInt
|
package/shim/checker/shim.go
CHANGED
|
@@ -20,6 +20,7 @@ import (
|
|
|
20
20
|
type Checker = innerchecker.Checker
|
|
21
21
|
type IndexInfo = innerchecker.IndexInfo
|
|
22
22
|
type Signature = innerchecker.Signature
|
|
23
|
+
type SignatureFlags = innerchecker.SignatureFlags
|
|
23
24
|
type SignatureKind = innerchecker.SignatureKind
|
|
24
25
|
type Type = innerchecker.Type
|
|
25
26
|
type TypeMapper = innerchecker.TypeMapper
|
|
@@ -216,6 +217,8 @@ func Checker_isSymbolAccessibleAsValue(recv *innerchecker.Checker, symbol *inner
|
|
|
216
217
|
}
|
|
217
218
|
|
|
218
219
|
const (
|
|
220
|
+
SignatureFlagsAbstract = innerchecker.SignatureFlagsAbstract
|
|
221
|
+
|
|
219
222
|
SignatureKindCall = innerchecker.SignatureKindCall
|
|
220
223
|
|
|
221
224
|
TypeMapperKindUnknown = innerchecker.TypeMapperKindUnknown
|
|
@@ -18,5 +18,15 @@ import (
|
|
|
18
18
|
// (type-erase, import-elision, runtime-syntax, module-transform, ...) for one
|
|
19
19
|
// source file, linked from the internal package via go:linkname.
|
|
20
20
|
//
|
|
21
|
+
// `sourceFile` is the marking target, not the file that gets transformed.
|
|
22
|
+
// Upstream reads it for two per-file constants (in-JS-file, JSX language
|
|
23
|
+
// variant) and then hands it to emitResolver.MarkLinkedReferencesRecursively,
|
|
24
|
+
// whose marks the import-elision transformer later reads back through
|
|
25
|
+
// EmitContext.ParseNode. A caller that runs a plugin pass first must therefore
|
|
26
|
+
// pass the PARSE tree here and the transformed tree to TransformSourceFile;
|
|
27
|
+
// upstream's own emitter passes one file to both only because it has nothing in
|
|
28
|
+
// between. Re-check this when the pin moves: a new use of the parameter inside
|
|
29
|
+
// getScriptTransformers could make the two roles diverge further.
|
|
30
|
+
//
|
|
21
31
|
//go:linkname GetScriptTransformers github.com/microsoft/typescript-go/internal/compiler.getScriptTransformers
|
|
22
32
|
func GetScriptTransformers(emitContext *innerprinter.EmitContext, host innerprinter.EmitHost, sourceFile *innerast.SourceFile) []*innertransformers.Transformer
|
|
@@ -7,9 +7,24 @@ export function createNativeProjectContextArgs(
|
|
|
7
7
|
): string[] {
|
|
8
8
|
return [
|
|
9
9
|
"--project-context-json=" +
|
|
10
|
-
|
|
11
|
-
...project.identity,
|
|
12
|
-
...(pluginConfigOrigin === undefined ? {} : { pluginConfigOrigin }),
|
|
13
|
-
}),
|
|
10
|
+
createNativeProjectContextJson(project, pluginConfigOrigin),
|
|
14
11
|
];
|
|
15
12
|
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The identity payload itself, for a caller that spawns a sidecar without going
|
|
16
|
+
* through the compiler's own argument list.
|
|
17
|
+
*
|
|
18
|
+
* Split from the flag so there is still exactly one place that decides what a
|
|
19
|
+
* sidecar is told about the project. A second caller assembling the same JSON,
|
|
20
|
+
* or slicing it back out of the flag, is how the two drift.
|
|
21
|
+
*/
|
|
22
|
+
export function createNativeProjectContextJson(
|
|
23
|
+
project: ITtscParsedProjectConfig,
|
|
24
|
+
pluginConfigOrigin?: string,
|
|
25
|
+
): string {
|
|
26
|
+
return JSON.stringify({
|
|
27
|
+
...project.identity,
|
|
28
|
+
...(pluginConfigOrigin === undefined ? {} : { pluginConfigOrigin }),
|
|
29
|
+
});
|
|
30
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -274,8 +274,16 @@ export interface RuntimeHookOptions {
|
|
|
274
274
|
* `require()` made from inside a CommonJS module that was itself reached
|
|
275
275
|
* through an ESM `import` (the interop translator loads it on the raw CJS
|
|
276
276
|
* path). The ESM graph goes through `registerHooks`; the CommonJS `require`
|
|
277
|
-
* graph goes through `Module._extensions` — the
|
|
278
|
-
*
|
|
277
|
+
* graph goes through `Module._extensions` and `Module._resolveFilename` — the
|
|
278
|
+
* canonical loader extension points `ts-node`/`tsx` use for the same reason.
|
|
279
|
+
*
|
|
280
|
+
* Both halves of that second graph are required, and they answer different
|
|
281
|
+
* questions. `_extensions` decides how a file that was _found_ is compiled, and
|
|
282
|
+
* Node reuses its keys when it probes an extensionless request, so
|
|
283
|
+
* `require("./x")` reaches `x.ts` for free. Nothing there resolves a request
|
|
284
|
+
* that already carries an extension: `require("./x.js")` backed only by `x.ts`
|
|
285
|
+
* is a resolution failure before any compiler is consulted, which is why the
|
|
286
|
+
* rescue is installed on `_resolveFilename` as well (samchon/ttsc#1280).
|
|
279
287
|
*/
|
|
280
288
|
export function installRuntimeHooks(options: RuntimeHookOptions = {}): void {
|
|
281
289
|
if (options.prepareEntry !== undefined) {
|
|
@@ -295,6 +303,7 @@ export function installRuntimeHooks(options: RuntimeHookOptions = {}): void {
|
|
|
295
303
|
}
|
|
296
304
|
registerHooks({ load, resolve });
|
|
297
305
|
installCommonJsHook();
|
|
306
|
+
installCommonJsResolveHook();
|
|
298
307
|
}
|
|
299
308
|
|
|
300
309
|
/**
|
|
@@ -339,6 +348,106 @@ function installCommonJsHook(): void {
|
|
|
339
348
|
}
|
|
340
349
|
}
|
|
341
350
|
|
|
351
|
+
/**
|
|
352
|
+
* Map a JavaScript spelling back to its TypeScript source on the CommonJS
|
|
353
|
+
* resolution path, so `require("./x.js")` finds `x.ts` when nothing emitted
|
|
354
|
+
* `x.js`.
|
|
355
|
+
*
|
|
356
|
+
* TypeScript asks authors to write the emitted `.js` extension in a relative
|
|
357
|
+
* specifier, so this spelling is the documented one rather than a mistake, and
|
|
358
|
+
* the ESM `resolve` hook has always rescued it. The CommonJS graph could not,
|
|
359
|
+
* and on Node 22 that graph is reached by every `require()` inside a CommonJS
|
|
360
|
+
* module the ESM loader evaluated — `module.registerHooks` sees the `import()`
|
|
361
|
+
* of that module and nothing within it. Node 24 routes the same `require`
|
|
362
|
+
* through the hooks, which is why the gap was only ever visible on the oldest
|
|
363
|
+
* runtime ttsx supports (`engines.node` is `>=22.15.0`).
|
|
364
|
+
*
|
|
365
|
+
* The wrapper only ever answers a request Node's own resolver already refused,
|
|
366
|
+
* so a resolution that succeeds is never perturbed, and a request no candidate
|
|
367
|
+
* satisfies rethrows Node's original error with its `MODULE_NOT_FOUND` code and
|
|
368
|
+
* `requireStack` intact. `require.resolve` shares this entry point and is
|
|
369
|
+
* rescued with it, except in its `{ paths }` form, which resolves against the
|
|
370
|
+
* caller's list rather than the parent this reads.
|
|
371
|
+
*/
|
|
372
|
+
function installCommonJsResolveHook(): void {
|
|
373
|
+
const internals = Module as unknown as {
|
|
374
|
+
_resolveFilename(
|
|
375
|
+
request: string,
|
|
376
|
+
parent: { filename?: string | null } | null | undefined,
|
|
377
|
+
isMain: boolean,
|
|
378
|
+
options?: unknown,
|
|
379
|
+
): string;
|
|
380
|
+
};
|
|
381
|
+
const original = internals._resolveFilename;
|
|
382
|
+
internals._resolveFilename = function resolveFilename(
|
|
383
|
+
this: unknown,
|
|
384
|
+
request: string,
|
|
385
|
+
parent: { filename?: string | null } | null | undefined,
|
|
386
|
+
isMain: boolean,
|
|
387
|
+
options?: unknown,
|
|
388
|
+
): string {
|
|
389
|
+
try {
|
|
390
|
+
return original.call(this, request, parent, isMain, options);
|
|
391
|
+
} catch (error) {
|
|
392
|
+
const rescued = rescueCommonJsRequest(request, parent, options);
|
|
393
|
+
if (rescued === null) {
|
|
394
|
+
throw error;
|
|
395
|
+
}
|
|
396
|
+
return rescued;
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* The TypeScript source a refused CommonJS request names, or `null`.
|
|
403
|
+
*
|
|
404
|
+
* Only a relative or absolute request can be rescued: a bare specifier is a
|
|
405
|
+
* package lookup, whose own resolver already probed every extension the
|
|
406
|
+
* installed `_extensions` keys declare.
|
|
407
|
+
*
|
|
408
|
+
* Two shapes decline before that. `_resolveFilename` is an internal entry point
|
|
409
|
+
* anything may call, so a non-string request reaches here as readily as a
|
|
410
|
+
* specifier does, and reading it would replace Node's own argument error with a
|
|
411
|
+
* `TypeError` from this file. And `require.resolve(request, { paths })`
|
|
412
|
+
* resolves against the caller's list, which this rescue does not consult, so
|
|
413
|
+
* answering it from the parent's directory would be a different question's
|
|
414
|
+
* answer.
|
|
415
|
+
*/
|
|
416
|
+
function rescueCommonJsRequest(
|
|
417
|
+
request: string,
|
|
418
|
+
parent: { filename?: string | null } | null | undefined,
|
|
419
|
+
options?: unknown,
|
|
420
|
+
): string | null {
|
|
421
|
+
if (typeof request !== "string") {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
if (
|
|
425
|
+
typeof options === "object" &&
|
|
426
|
+
options !== null &&
|
|
427
|
+
Array.isArray((options as { paths?: unknown }).paths)
|
|
428
|
+
) {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
let base: string;
|
|
432
|
+
if (path.isAbsolute(request)) {
|
|
433
|
+
base = request;
|
|
434
|
+
} else if (isRelativeSpecifier(request)) {
|
|
435
|
+
const from = parent?.filename;
|
|
436
|
+
if (typeof from !== "string") {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
base = path.resolve(path.dirname(from), request);
|
|
440
|
+
} else {
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
for (const candidate of typescriptSourcesForJavaScriptSpecifier(base)) {
|
|
444
|
+
if (isFile(candidate)) {
|
|
445
|
+
return candidate;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
|
|
342
451
|
/**
|
|
343
452
|
* The module format of the entry source file, derived from the entry project's
|
|
344
453
|
* compiler options (via the runtime manifest) the same way the served files are
|