ttsc 0.8.1 → 0.10.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/README.md +39 -68
- package/cmd/ttsc/api_compile.go +109 -115
- package/cmd/ttsc/api_transform.go +54 -51
- package/cmd/ttsc/main.go +103 -121
- package/driver/program.go +30 -2
- package/driver/rewrite.go +126 -9
- package/go.mod +2 -0
- package/lib/TtscCompiler.js +28 -46
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/compiler/internal/buildNativeCompiler.js +8 -38
- package/lib/compiler/internal/buildNativeCompiler.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.js +36 -63
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/project/readProjectConfig.js +108 -60
- package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
- package/lib/compiler/internal/project/resolveProjectConfig.js +15 -45
- package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -1
- package/lib/compiler/internal/resolveBinary.js +10 -40
- package/lib/compiler/internal/resolveBinary.js.map +1 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.js +21 -48
- package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
- package/lib/compiler/internal/resolveTsgo.js +14 -44
- package/lib/compiler/internal/resolveTsgo.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +7 -0
- package/lib/compiler/internal/runBuild.js +47 -66
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.js +18 -48
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +41 -75
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/launcher/internal/getCompilerVersionText.js +7 -37
- package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.js +48 -69
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +53 -64
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +328 -57
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/plugin/internal/buildSourcePlugin.d.ts +8 -0
- package/lib/plugin/internal/buildSourcePlugin.js +287 -139
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.d.ts +2 -0
- package/lib/plugin/internal/loadProjectPlugins.js +197 -9
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscCompilerContext.d.ts +16 -3
- package/lib/structures/ITtscCompilerResult.d.ts +4 -0
- package/lib/structures/ITtscCompilerTransformation.d.ts +2 -0
- package/lib/structures/ITtscPluginFactoryContext.d.ts +6 -3
- package/lib/structures/ITtscProjectPluginConfig.d.ts +8 -7
- package/lib/structures/internal/ITtscParsedProjectConfig.d.ts +2 -0
- package/lib/structures/internal/ITtscProjectLocatorOptions.d.ts +2 -0
- package/lib/structures/internal/TtscCommonOptions.d.ts +2 -0
- package/package.json +9 -14
- package/shim/diagnosticwriter/lint.go +8 -0
- package/shim/printer/go.mod +5 -0
- package/shim/printer/shim.go +23 -0
- package/src/TtscCompiler.ts +20 -5
- package/src/compiler/internal/buildNativeCompiler.ts +2 -2
- package/src/compiler/internal/compileProjectInMemory.ts +21 -16
- package/src/compiler/internal/project/readProjectConfig.ts +134 -35
- package/src/compiler/internal/project/resolveProjectConfig.ts +2 -2
- package/src/compiler/internal/resolveBinary.ts +2 -2
- package/src/compiler/internal/resolveEmittedJavaScript.ts +11 -7
- package/src/compiler/internal/resolveTsgo.ts +2 -2
- package/src/compiler/internal/runBuild.ts +34 -21
- package/src/compiler/internal/runSingleFileEmit.ts +3 -3
- package/src/compiler/internal/transformProjectInMemory.ts +37 -37
- package/src/launcher/internal/getCompilerVersionText.ts +2 -2
- package/src/launcher/internal/prepareExecution.ts +14 -4
- package/src/launcher/internal/runTtsc.ts +30 -4
- package/src/launcher/internal/runTtsx.ts +377 -26
- package/src/plugin/internal/buildSourcePlugin.ts +321 -50
- package/src/plugin/internal/loadProjectPlugins.ts +266 -10
- package/src/structures/ITtscCompilerContext.ts +17 -3
- package/src/structures/ITtscCompilerResult.ts +5 -0
- package/src/structures/ITtscCompilerTransformation.ts +3 -0
- package/src/structures/ITtscPluginFactoryContext.ts +6 -3
- package/src/structures/ITtscProjectPluginConfig.ts +8 -7
- package/src/structures/internal/ITtscParsedProjectConfig.ts +2 -0
- package/src/structures/internal/ITtscProjectLocatorOptions.ts +2 -0
- package/src/structures/internal/TtscCommonOptions.ts +2 -0
- package/utility/host.go +622 -20
- package/cmd/ttsc/main_test.go +0 -288
- package/test/compiler.test.ts +0 -422
- package/test/platform.test.ts +0 -12
- package/test/project.test.ts +0 -197
- package/test/source-build.test.ts +0 -45
- package/test/tsgo.test.ts +0 -69
|
@@ -1,101 +1,92 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
35
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
6
|
exports.buildSourcePlugin = buildSourcePlugin;
|
|
7
|
+
exports.computeCacheKey = computeCacheKey;
|
|
37
8
|
const node_child_process_1 = require("node:child_process");
|
|
38
|
-
const
|
|
39
|
-
const
|
|
9
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
10
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
40
11
|
const node_module_1 = require("node:module");
|
|
41
|
-
const
|
|
12
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
13
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
42
14
|
const GO_MOD_SEARCH_MAX_DEPTH = 3;
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"build",
|
|
48
|
-
"vendor",
|
|
49
|
-
"lib",
|
|
50
|
-
]);
|
|
15
|
+
const TTSC_GO_MODULE_PATH = "github.com/samchon/ttsc/packages/ttsc";
|
|
16
|
+
const TSGO_GO_MODULE_PATH = "github.com/microsoft/typescript-go";
|
|
17
|
+
const PRUNE_DIRS = new Set(["node_modules", ".git", ".ttsc"]);
|
|
18
|
+
const GENERATED_WORKSPACE_FILES = new Set(["go.work", "go.work.sum"]);
|
|
51
19
|
/** Build one Go source plugin into a cached executable. */
|
|
52
20
|
function buildSourcePlugin(opts) {
|
|
53
21
|
const { dir, entry, source } = resolveSourceBuildTarget(opts);
|
|
22
|
+
const overlayDirs = opts.overlayDirs ?? findTtscOverlayDirs();
|
|
23
|
+
const goBinary = resolveGoCompiler();
|
|
24
|
+
ensureExecutableGoToolchain(goBinary);
|
|
54
25
|
const key = computeCacheKey({
|
|
55
26
|
dir,
|
|
56
27
|
entry,
|
|
28
|
+
goBinary,
|
|
29
|
+
overlayDirs,
|
|
57
30
|
ttscVersion: opts.ttscVersion,
|
|
58
31
|
tsgoVersion: opts.tsgoVersion,
|
|
59
32
|
});
|
|
60
33
|
const root = resolvePluginCacheRoot(opts.baseDir, opts.cacheDir);
|
|
61
|
-
const cacheDir =
|
|
34
|
+
const cacheDir = node_path_1.default.join(root, key);
|
|
62
35
|
const binaryName = process.platform === "win32" ? "plugin.exe" : "plugin";
|
|
63
|
-
const binaryPath =
|
|
64
|
-
if (
|
|
36
|
+
const binaryPath = node_path_1.default.join(cacheDir, binaryName);
|
|
37
|
+
if (node_fs_1.default.existsSync(binaryPath)) {
|
|
65
38
|
return binaryPath;
|
|
66
39
|
}
|
|
67
|
-
|
|
40
|
+
node_fs_1.default.mkdirSync(cacheDir, { recursive: true });
|
|
68
41
|
const label = opts.label ?? "source plugin";
|
|
69
42
|
if (opts.quiet !== true) {
|
|
70
43
|
process.stderr.write(`ttsc: building ${label} "${opts.pluginName}" from ${source} (this runs once per cache key)\n`);
|
|
71
44
|
}
|
|
72
|
-
const scratchDir =
|
|
45
|
+
const scratchDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), `ttsc-plugin-${key}-`));
|
|
73
46
|
try {
|
|
74
47
|
materializeScratchDir(dir, scratchDir);
|
|
75
|
-
writeGoWork(scratchDir,
|
|
48
|
+
writeGoWork(scratchDir, overlayDirs, goBinary, opts.pluginName);
|
|
76
49
|
const scratchBinaryName = process.platform === "win32" ? ".ttsc-plugin.exe" : ".ttsc-plugin";
|
|
77
|
-
runGoBuild(scratchDir, entry, scratchBinaryName, opts.pluginName);
|
|
78
|
-
const builtBinary =
|
|
79
|
-
|
|
80
|
-
if (process.platform !== "win32") {
|
|
81
|
-
fs.chmodSync(binaryPath, 0o755);
|
|
82
|
-
}
|
|
50
|
+
runGoBuild(scratchDir, entry, scratchBinaryName, opts.pluginName, goBinary);
|
|
51
|
+
const builtBinary = node_path_1.default.join(scratchDir, scratchBinaryName);
|
|
52
|
+
publishBuiltBinary(builtBinary, binaryPath);
|
|
83
53
|
return binaryPath;
|
|
84
54
|
}
|
|
85
55
|
finally {
|
|
86
|
-
|
|
56
|
+
node_fs_1.default.rmSync(scratchDir, { recursive: true, force: true });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function publishBuiltBinary(builtBinary, binaryPath) {
|
|
60
|
+
const pending = `${binaryPath}.${process.pid}.${Date.now()}-${Math.random()
|
|
61
|
+
.toString(16)
|
|
62
|
+
.slice(2)}.tmp`;
|
|
63
|
+
node_fs_1.default.copyFileSync(builtBinary, pending);
|
|
64
|
+
if (process.platform !== "win32") {
|
|
65
|
+
node_fs_1.default.chmodSync(pending, 0o755);
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
node_fs_1.default.renameSync(pending, binaryPath);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
node_fs_1.default.rmSync(pending, { force: true });
|
|
72
|
+
const code = error.code;
|
|
73
|
+
if ((code === "EEXIST" || code === "EPERM" || code === "EACCES") &&
|
|
74
|
+
node_fs_1.default.existsSync(binaryPath)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
throw error;
|
|
87
78
|
}
|
|
88
79
|
}
|
|
89
80
|
function resolveSourceBuildTarget(opts) {
|
|
90
|
-
const source =
|
|
81
|
+
const source = node_path_1.default.isAbsolute(opts.source)
|
|
91
82
|
? opts.source
|
|
92
|
-
:
|
|
93
|
-
if (!
|
|
83
|
+
: node_path_1.default.resolve(opts.baseDir, opts.source);
|
|
84
|
+
if (!node_fs_1.default.existsSync(source)) {
|
|
94
85
|
throw new Error(`ttsc: plugin "${opts.pluginName}" source does not exist: ${source}`);
|
|
95
86
|
}
|
|
96
|
-
const stat =
|
|
97
|
-
const packageDir = stat.isFile() &&
|
|
98
|
-
?
|
|
87
|
+
const stat = node_fs_1.default.statSync(source);
|
|
88
|
+
const packageDir = stat.isFile() && node_path_1.default.basename(source) === "go.mod"
|
|
89
|
+
? node_path_1.default.dirname(source)
|
|
99
90
|
: stat.isDirectory()
|
|
100
91
|
? source
|
|
101
92
|
: null;
|
|
@@ -106,8 +97,8 @@ function resolveSourceBuildTarget(opts) {
|
|
|
106
97
|
if (goMod === null) {
|
|
107
98
|
throw new Error(`ttsc: plugin "${opts.pluginName}" source must be inside a Go module with go.mod within ${GO_MOD_SEARCH_MAX_DEPTH} parent directories: ${source}`);
|
|
108
99
|
}
|
|
109
|
-
const dir =
|
|
110
|
-
const rel =
|
|
100
|
+
const dir = node_path_1.default.dirname(goMod);
|
|
101
|
+
const rel = node_path_1.default.relative(dir, packageDir).replace(/\\/g, "/");
|
|
111
102
|
return {
|
|
112
103
|
dir,
|
|
113
104
|
entry: rel === "" ? "." : `./${rel}`,
|
|
@@ -115,15 +106,15 @@ function resolveSourceBuildTarget(opts) {
|
|
|
115
106
|
};
|
|
116
107
|
}
|
|
117
108
|
function findNearestGoMod(from, maxDepth) {
|
|
118
|
-
let current =
|
|
109
|
+
let current = node_path_1.default.resolve(from);
|
|
119
110
|
let depth = 0;
|
|
120
111
|
while (true) {
|
|
121
|
-
const candidate =
|
|
122
|
-
if (
|
|
112
|
+
const candidate = node_path_1.default.join(current, "go.mod");
|
|
113
|
+
if (node_fs_1.default.existsSync(candidate))
|
|
123
114
|
return candidate;
|
|
124
115
|
if (depth >= maxDepth)
|
|
125
116
|
return null;
|
|
126
|
-
const parent =
|
|
117
|
+
const parent = node_path_1.default.dirname(current);
|
|
127
118
|
if (parent === current)
|
|
128
119
|
return null;
|
|
129
120
|
current = parent;
|
|
@@ -131,52 +122,139 @@ function findNearestGoMod(from, maxDepth) {
|
|
|
131
122
|
}
|
|
132
123
|
}
|
|
133
124
|
function materializeScratchDir(source, scratch) {
|
|
134
|
-
|
|
135
|
-
|
|
125
|
+
node_fs_1.default.mkdirSync(scratch, { recursive: true });
|
|
126
|
+
node_fs_1.default.cpSync(source, scratch, {
|
|
136
127
|
recursive: true,
|
|
137
128
|
filter: (src) => {
|
|
138
|
-
const base =
|
|
139
|
-
if (
|
|
129
|
+
const base = node_path_1.default.basename(src);
|
|
130
|
+
if (shouldPruneDirectory(base))
|
|
140
131
|
return false;
|
|
141
|
-
if (base
|
|
132
|
+
if (shouldOmitSourceFile(base))
|
|
142
133
|
return false;
|
|
143
134
|
return true;
|
|
144
135
|
},
|
|
145
136
|
});
|
|
146
137
|
}
|
|
147
|
-
function writeGoWork(scratchDir, useDirs) {
|
|
138
|
+
function writeGoWork(scratchDir, useDirs, goBinary, pluginName) {
|
|
139
|
+
const goModReader = createGoModReader(goBinary, pluginName);
|
|
140
|
+
validateSourceReplacements(scratchDir, useDirs, goModReader, pluginName);
|
|
148
141
|
const useLines = ["\t."];
|
|
149
142
|
for (const dir of useDirs) {
|
|
150
143
|
useLines.push(`\t${dir.replace(/\\/g, "/")}`);
|
|
151
144
|
}
|
|
152
|
-
const replaceLines = sourceBuildWorkspaceReplacements(useDirs);
|
|
145
|
+
const replaceLines = sourceBuildWorkspaceReplacements(useDirs, goModReader);
|
|
153
146
|
const replaceBlock = replaceLines.length === 0 ? "" : `\n\n${replaceLines.join("\n")}\n`;
|
|
154
147
|
const goWork = `go 1.26\n\nuse (\n${useLines.join("\n")}\n)${replaceBlock}`;
|
|
155
|
-
|
|
148
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(scratchDir, "go.work"), goWork, "utf8");
|
|
149
|
+
}
|
|
150
|
+
function validateSourceReplacements(scratchDir, useDirs, goModReader, pluginName) {
|
|
151
|
+
const sourceInfo = goModReader.read(scratchDir);
|
|
152
|
+
if (sourceInfo.modulePath === TTSC_GO_MODULE_PATH) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const sourceReplacements = sourceInfo.replacements;
|
|
156
|
+
if (sourceReplacements.length === 0) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const overlayModules = collectOverlayModulePaths(useDirs, goModReader);
|
|
160
|
+
for (const replacement of sourceReplacements) {
|
|
161
|
+
if (isTtscManagedModulePath(replacement.modulePath) ||
|
|
162
|
+
overlayModules.has(replacement.modulePath)) {
|
|
163
|
+
throw new Error(`ttsc: plugin "${pluginName}" go.mod replaces ttsc-managed module ` +
|
|
164
|
+
`${JSON.stringify(replacement.modulePath)}. Remove this replace directive; ` +
|
|
165
|
+
`ttsc supplies its own compiler and shim modules while building source plugins.`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
156
168
|
}
|
|
157
|
-
function sourceBuildWorkspaceReplacements(useDirs) {
|
|
158
|
-
const ttscRoot = useDirs.find((dir) =>
|
|
169
|
+
function sourceBuildWorkspaceReplacements(useDirs, goModReader) {
|
|
170
|
+
const ttscRoot = useDirs.find((dir) => goModReader.read(dir).modulePath === TTSC_GO_MODULE_PATH);
|
|
159
171
|
if (!ttscRoot) {
|
|
160
172
|
return [];
|
|
161
173
|
}
|
|
162
174
|
return [
|
|
163
|
-
`replace
|
|
175
|
+
`replace ${TTSC_GO_MODULE_PATH} v0.0.0 => ${ttscRoot.replace(/\\/g, "/")}`,
|
|
164
176
|
];
|
|
165
177
|
}
|
|
166
|
-
function
|
|
178
|
+
function createGoModReader(goBinary, pluginName) {
|
|
179
|
+
const cache = new Map();
|
|
180
|
+
return {
|
|
181
|
+
read(dir) {
|
|
182
|
+
const resolved = node_path_1.default.resolve(dir);
|
|
183
|
+
const cached = cache.get(resolved);
|
|
184
|
+
if (cached !== undefined) {
|
|
185
|
+
return cached;
|
|
186
|
+
}
|
|
187
|
+
const info = readGoModInfo(resolved, goBinary, pluginName);
|
|
188
|
+
cache.set(resolved, info);
|
|
189
|
+
return info;
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function readGoModInfo(dir, goBinary, pluginName) {
|
|
194
|
+
if (!node_fs_1.default.existsSync(node_path_1.default.join(dir, "go.mod"))) {
|
|
195
|
+
return emptyGoModInfo();
|
|
196
|
+
}
|
|
197
|
+
const result = (0, node_child_process_1.spawnSync)(goBinary, ["mod", "edit", "-json"], {
|
|
198
|
+
cwd: dir,
|
|
199
|
+
encoding: "utf8",
|
|
200
|
+
env: goBuildEnv(goBinary),
|
|
201
|
+
maxBuffer: 1024 * 1024 * 16,
|
|
202
|
+
windowsHide: true,
|
|
203
|
+
});
|
|
204
|
+
if (result.error) {
|
|
205
|
+
if (result.error.code === "ENOENT") {
|
|
206
|
+
throw new Error(goToolchainNotFoundMessage(pluginName));
|
|
207
|
+
}
|
|
208
|
+
throw new Error(`ttsc: reading go.mod for plugin "${pluginName}" failed to spawn ${goBinary}: ${result.error.message}`);
|
|
209
|
+
}
|
|
210
|
+
if (result.status !== 0) {
|
|
211
|
+
throw new Error(`ttsc: reading go.mod for plugin "${pluginName}" failed:\n${result.stderr || result.stdout}`);
|
|
212
|
+
}
|
|
213
|
+
let json;
|
|
167
214
|
try {
|
|
168
|
-
|
|
169
|
-
return new RegExp(`^module\\s+${escapeRegExp(modulePath)}\\s*$`, "m").test(goMod);
|
|
215
|
+
json = JSON.parse(result.stdout);
|
|
170
216
|
}
|
|
171
|
-
catch {
|
|
172
|
-
|
|
217
|
+
catch (error) {
|
|
218
|
+
throw new Error(`ttsc: reading go.mod for plugin "${pluginName}" returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
173
219
|
}
|
|
220
|
+
return {
|
|
221
|
+
modulePath: json.Module?.Path ?? null,
|
|
222
|
+
replacements: (json.Replace ?? [])
|
|
223
|
+
.map(jsonReplacementToGoModReplacement)
|
|
224
|
+
.filter((replacement) => replacement !== null),
|
|
225
|
+
};
|
|
174
226
|
}
|
|
175
|
-
function
|
|
176
|
-
return
|
|
227
|
+
function emptyGoModInfo() {
|
|
228
|
+
return {
|
|
229
|
+
modulePath: null,
|
|
230
|
+
replacements: [],
|
|
231
|
+
};
|
|
177
232
|
}
|
|
178
|
-
function
|
|
179
|
-
const
|
|
233
|
+
function jsonReplacementToGoModReplacement(replacement) {
|
|
234
|
+
const modulePath = replacement.Old?.Path;
|
|
235
|
+
if (modulePath === undefined) {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
modulePath,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function collectOverlayModulePaths(dirs, goModReader) {
|
|
243
|
+
const out = new Set();
|
|
244
|
+
for (const dir of dirs) {
|
|
245
|
+
const modulePath = goModReader.read(dir).modulePath;
|
|
246
|
+
if (modulePath !== null) {
|
|
247
|
+
out.add(modulePath);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return out;
|
|
251
|
+
}
|
|
252
|
+
function isTtscManagedModulePath(modulePath) {
|
|
253
|
+
return (modulePath === TTSC_GO_MODULE_PATH ||
|
|
254
|
+
modulePath === TSGO_GO_MODULE_PATH ||
|
|
255
|
+
modulePath.startsWith("github.com/microsoft/typescript-go/shim/"));
|
|
256
|
+
}
|
|
257
|
+
function runGoBuild(cwd, entry, binaryName, pluginName, goBinary) {
|
|
180
258
|
ensureExecutableGoToolchain(goBinary);
|
|
181
259
|
const result = (0, node_child_process_1.spawnSync)(goBinary, ["build", "-o", binaryName, entry], {
|
|
182
260
|
cwd,
|
|
@@ -187,9 +265,7 @@ function runGoBuild(cwd, entry, binaryName, pluginName) {
|
|
|
187
265
|
});
|
|
188
266
|
if (result.error) {
|
|
189
267
|
if (result.error.code === "ENOENT") {
|
|
190
|
-
throw new Error(
|
|
191
|
-
`Reinstall ttsc with optional dependencies so the bundled Go compiler is present, ` +
|
|
192
|
-
`or set TTSC_GO_BINARY to an absolute path.`);
|
|
268
|
+
throw new Error(goToolchainNotFoundMessage(pluginName));
|
|
193
269
|
}
|
|
194
270
|
throw new Error(`ttsc: building plugin "${pluginName}" failed to spawn ${goBinary}: ${result.error.message}`);
|
|
195
271
|
}
|
|
@@ -197,6 +273,11 @@ function runGoBuild(cwd, entry, binaryName, pluginName) {
|
|
|
197
273
|
throw new Error(`ttsc: building plugin "${pluginName}" via "go build" failed:\n${result.stderr || result.stdout}`);
|
|
198
274
|
}
|
|
199
275
|
}
|
|
276
|
+
function goToolchainNotFoundMessage(pluginName) {
|
|
277
|
+
return (`ttsc: building plugin "${pluginName}" failed because the Go toolchain was not found. ` +
|
|
278
|
+
`Reinstall ttsc with optional dependencies so the bundled Go compiler is present, ` +
|
|
279
|
+
`or set TTSC_GO_BINARY to an absolute path.`);
|
|
280
|
+
}
|
|
200
281
|
function goBuildEnv(goBinary) {
|
|
201
282
|
const env = { ...process.env };
|
|
202
283
|
const goRoot = inferGoRoot(goBinary);
|
|
@@ -206,32 +287,32 @@ function goBuildEnv(goBinary) {
|
|
|
206
287
|
return env;
|
|
207
288
|
}
|
|
208
289
|
function inferGoRoot(goBinary) {
|
|
209
|
-
if (!
|
|
290
|
+
if (!node_path_1.default.isAbsolute(goBinary))
|
|
210
291
|
return null;
|
|
211
|
-
const binDir =
|
|
212
|
-
if (
|
|
292
|
+
const binDir = node_path_1.default.dirname(goBinary);
|
|
293
|
+
if (node_path_1.default.basename(binDir) !== "bin")
|
|
213
294
|
return null;
|
|
214
|
-
const goRoot =
|
|
215
|
-
return
|
|
295
|
+
const goRoot = node_path_1.default.dirname(binDir);
|
|
296
|
+
return node_fs_1.default.existsSync(node_path_1.default.join(goRoot, "src", "runtime")) ? goRoot : null;
|
|
216
297
|
}
|
|
217
298
|
function ensureExecutableGoToolchain(goBinary) {
|
|
218
299
|
if (process.platform === "win32")
|
|
219
300
|
return;
|
|
220
|
-
if (!
|
|
301
|
+
if (!node_path_1.default.isAbsolute(goBinary) || !node_fs_1.default.existsSync(goBinary))
|
|
221
302
|
return;
|
|
222
303
|
try {
|
|
223
|
-
|
|
304
|
+
node_fs_1.default.chmodSync(goBinary, 0o755);
|
|
224
305
|
const goRoot = inferGoRoot(goBinary);
|
|
225
306
|
if (!goRoot)
|
|
226
307
|
return;
|
|
227
|
-
const gofmt =
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
const toolDir =
|
|
231
|
-
if (!
|
|
308
|
+
const gofmt = node_path_1.default.join(node_path_1.default.dirname(goBinary), "gofmt");
|
|
309
|
+
if (node_fs_1.default.existsSync(gofmt))
|
|
310
|
+
node_fs_1.default.chmodSync(gofmt, 0o755);
|
|
311
|
+
const toolDir = node_path_1.default.join(goRoot, "pkg", "tool");
|
|
312
|
+
if (!node_fs_1.default.existsSync(toolDir))
|
|
232
313
|
return;
|
|
233
314
|
for (const file of walkToolFiles(toolDir)) {
|
|
234
|
-
|
|
315
|
+
node_fs_1.default.chmodSync(file, 0o755);
|
|
235
316
|
}
|
|
236
317
|
}
|
|
237
318
|
catch {
|
|
@@ -242,13 +323,13 @@ function walkToolFiles(dir) {
|
|
|
242
323
|
const out = [];
|
|
243
324
|
let entries;
|
|
244
325
|
try {
|
|
245
|
-
entries =
|
|
326
|
+
entries = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
246
327
|
}
|
|
247
328
|
catch {
|
|
248
329
|
return out;
|
|
249
330
|
}
|
|
250
331
|
for (const entry of entries) {
|
|
251
|
-
const file =
|
|
332
|
+
const file = node_path_1.default.join(dir, entry.name);
|
|
252
333
|
if (entry.isDirectory()) {
|
|
253
334
|
out.push(...walkToolFiles(file));
|
|
254
335
|
}
|
|
@@ -259,13 +340,13 @@ function walkToolFiles(dir) {
|
|
|
259
340
|
return out;
|
|
260
341
|
}
|
|
261
342
|
function findTtscOverlayDirs() {
|
|
262
|
-
const ttscRoot =
|
|
343
|
+
const ttscRoot = node_path_1.default.resolve(__dirname, "..", "..", "..");
|
|
263
344
|
const dirs = [];
|
|
264
|
-
if (
|
|
345
|
+
if (node_fs_1.default.existsSync(node_path_1.default.join(ttscRoot, "go.mod"))) {
|
|
265
346
|
dirs.push(ttscRoot);
|
|
266
347
|
}
|
|
267
|
-
const shimRoot =
|
|
268
|
-
if (
|
|
348
|
+
const shimRoot = node_path_1.default.join(ttscRoot, "shim");
|
|
349
|
+
if (node_fs_1.default.existsSync(shimRoot)) {
|
|
269
350
|
walkForGoMod(shimRoot, dirs);
|
|
270
351
|
}
|
|
271
352
|
dirs.sort();
|
|
@@ -274,7 +355,7 @@ function findTtscOverlayDirs() {
|
|
|
274
355
|
function walkForGoMod(dir, out) {
|
|
275
356
|
let entries;
|
|
276
357
|
try {
|
|
277
|
-
entries =
|
|
358
|
+
entries = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
278
359
|
}
|
|
279
360
|
catch {
|
|
280
361
|
return;
|
|
@@ -291,28 +372,28 @@ function walkForGoMod(dir, out) {
|
|
|
291
372
|
for (const entry of entries) {
|
|
292
373
|
if (!entry.isDirectory())
|
|
293
374
|
continue;
|
|
294
|
-
if (
|
|
375
|
+
if (shouldPruneDirectory(entry.name))
|
|
295
376
|
continue;
|
|
296
|
-
walkForGoMod(
|
|
377
|
+
walkForGoMod(node_path_1.default.join(dir, entry.name), out);
|
|
297
378
|
}
|
|
298
379
|
}
|
|
299
380
|
function resolvePluginCacheRoot(projectRoot, cacheDir) {
|
|
300
381
|
if (cacheDir) {
|
|
301
|
-
return
|
|
382
|
+
return node_path_1.default.resolve(projectRoot, cacheDir, "plugins");
|
|
302
383
|
}
|
|
303
384
|
if (process.env.TTSC_CACHE_DIR) {
|
|
304
|
-
return
|
|
385
|
+
return node_path_1.default.resolve(process.env.TTSC_CACHE_DIR, "plugins");
|
|
305
386
|
}
|
|
306
|
-
const root =
|
|
307
|
-
const nodeModules =
|
|
387
|
+
const root = node_path_1.default.resolve(projectRoot);
|
|
388
|
+
const nodeModules = node_path_1.default.join(root, "node_modules");
|
|
308
389
|
if (isDirectory(nodeModules)) {
|
|
309
|
-
return
|
|
390
|
+
return node_path_1.default.join(nodeModules, ".ttsc", "plugins");
|
|
310
391
|
}
|
|
311
|
-
return
|
|
392
|
+
return node_path_1.default.join(root, ".ttsc", "plugins");
|
|
312
393
|
}
|
|
313
394
|
function isDirectory(candidate) {
|
|
314
395
|
try {
|
|
315
|
-
return
|
|
396
|
+
return node_fs_1.default.statSync(candidate).isDirectory();
|
|
316
397
|
}
|
|
317
398
|
catch {
|
|
318
399
|
return false;
|
|
@@ -328,30 +409,41 @@ function resolveGoCompiler() {
|
|
|
328
409
|
catch {
|
|
329
410
|
/* fall through */
|
|
330
411
|
}
|
|
331
|
-
const platformPackage =
|
|
332
|
-
if (
|
|
412
|
+
const platformPackage = node_path_1.default.resolve(__dirname, "..", "..", "..", "..", `ttsc-${process.platform}-${process.arch}`, "bin", "go", "bin", process.platform === "win32" ? "go.exe" : "go");
|
|
413
|
+
if (node_fs_1.default.existsSync(platformPackage))
|
|
333
414
|
return platformPackage;
|
|
334
|
-
const local =
|
|
335
|
-
if (
|
|
415
|
+
const local = node_path_1.default.resolve(__dirname, "..", "..", "..", "..", "native", "go", "bin", process.platform === "win32" ? "go.exe" : "go");
|
|
416
|
+
if (node_fs_1.default.existsSync(local))
|
|
336
417
|
return local;
|
|
337
|
-
const homeSdk =
|
|
338
|
-
if (
|
|
418
|
+
const homeSdk = node_path_1.default.join(process.env.HOME ?? "", "go-sdk", "go", "bin", process.platform === "win32" ? "go.exe" : "go");
|
|
419
|
+
if (node_fs_1.default.existsSync(homeSdk))
|
|
339
420
|
return homeSdk;
|
|
340
421
|
return "go";
|
|
341
422
|
}
|
|
342
423
|
function computeCacheKey(inputs) {
|
|
343
|
-
const hash =
|
|
424
|
+
const hash = node_crypto_1.default.createHash("sha256");
|
|
344
425
|
hash.update(`ttsc=${inputs.ttscVersion}\n`);
|
|
345
426
|
hash.update(`tsgo=${inputs.tsgoVersion}\n`);
|
|
346
427
|
hash.update(`platform=${process.platform}/${process.arch}\n`);
|
|
347
428
|
hash.update(`entry=${inputs.entry}\n`);
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
429
|
+
if (inputs.goBinary !== undefined) {
|
|
430
|
+
hash.update(`go=${resolveGoCompilerIdentity(inputs.goBinary)}\n`);
|
|
431
|
+
}
|
|
432
|
+
hashSourceDirectory(hash, "plugin", inputs.dir);
|
|
433
|
+
for (const [index, dir] of [...(inputs.overlayDirs ?? [])].sort().entries()) {
|
|
434
|
+
hashSourceDirectory(hash, `overlay:${index}`, dir);
|
|
352
435
|
}
|
|
353
436
|
return hash.digest("hex").slice(0, 32);
|
|
354
437
|
}
|
|
438
|
+
function hashSourceDirectory(hash, label, root) {
|
|
439
|
+
hash.update(`dir=${label}\n`);
|
|
440
|
+
for (const file of collectSourceFiles(root)) {
|
|
441
|
+
const rel = node_path_1.default.relative(root, file).replace(/\\/g, "/");
|
|
442
|
+
hash.update(`f=${rel}\n`);
|
|
443
|
+
hash.update(node_fs_1.default.readFileSync(file));
|
|
444
|
+
hash.update("\n");
|
|
445
|
+
}
|
|
446
|
+
}
|
|
355
447
|
function collectSourceFiles(root) {
|
|
356
448
|
const out = [];
|
|
357
449
|
walk(root, out);
|
|
@@ -361,29 +453,85 @@ function collectSourceFiles(root) {
|
|
|
361
453
|
function walk(dir, out) {
|
|
362
454
|
let entries;
|
|
363
455
|
try {
|
|
364
|
-
entries =
|
|
456
|
+
entries = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
365
457
|
}
|
|
366
458
|
catch {
|
|
367
459
|
return;
|
|
368
460
|
}
|
|
369
461
|
for (const entry of entries) {
|
|
370
|
-
|
|
371
|
-
continue;
|
|
372
|
-
const full = path.join(dir, entry.name);
|
|
462
|
+
const full = node_path_1.default.join(dir, entry.name);
|
|
373
463
|
if (entry.isDirectory()) {
|
|
464
|
+
if (shouldPruneDirectory(entry.name))
|
|
465
|
+
continue;
|
|
374
466
|
walk(full, out);
|
|
375
467
|
continue;
|
|
376
468
|
}
|
|
377
469
|
if (!entry.isFile())
|
|
378
470
|
continue;
|
|
471
|
+
if (shouldOmitSourceFile(entry.name))
|
|
472
|
+
continue;
|
|
379
473
|
if (!isHashableFile(entry.name))
|
|
380
474
|
continue;
|
|
381
475
|
out.push(full);
|
|
382
476
|
}
|
|
383
477
|
}
|
|
478
|
+
function shouldPruneDirectory(name) {
|
|
479
|
+
return PRUNE_DIRS.has(name);
|
|
480
|
+
}
|
|
481
|
+
function shouldOmitSourceFile(name) {
|
|
482
|
+
return GENERATED_WORKSPACE_FILES.has(name);
|
|
483
|
+
}
|
|
384
484
|
function isHashableFile(name) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
485
|
+
return !name.endsWith("~");
|
|
486
|
+
}
|
|
487
|
+
function resolveGoCompilerIdentity(goBinary) {
|
|
488
|
+
const resolved = resolveExecutableIdentityPath(goBinary);
|
|
489
|
+
const version = (0, node_child_process_1.spawnSync)(goBinary, ["version"], {
|
|
490
|
+
encoding: "utf8",
|
|
491
|
+
windowsHide: true,
|
|
492
|
+
});
|
|
493
|
+
const versionText = version.error !== undefined
|
|
494
|
+
? version.error.message
|
|
495
|
+
: `${version.status ?? 0}:${version.stdout}${version.stderr}`;
|
|
496
|
+
let statText = "";
|
|
497
|
+
try {
|
|
498
|
+
const stat = node_fs_1.default.statSync(resolved);
|
|
499
|
+
statText = `${stat.size}:${stat.mtimeMs}`;
|
|
500
|
+
}
|
|
501
|
+
catch {
|
|
502
|
+
statText = "missing";
|
|
503
|
+
}
|
|
504
|
+
return `${goBinary}:${resolved}:${statText}:${versionText}`;
|
|
505
|
+
}
|
|
506
|
+
function resolveExecutableIdentityPath(binary) {
|
|
507
|
+
if (node_path_1.default.isAbsolute(binary)) {
|
|
508
|
+
return resolveRealPath(binary);
|
|
509
|
+
}
|
|
510
|
+
if (binary.includes(node_path_1.default.sep)) {
|
|
511
|
+
return resolveRealPath(node_path_1.default.resolve(binary));
|
|
512
|
+
}
|
|
513
|
+
for (const dir of (process.env.PATH ?? "").split(node_path_1.default.delimiter)) {
|
|
514
|
+
if (dir.length === 0)
|
|
515
|
+
continue;
|
|
516
|
+
const candidate = node_path_1.default.join(dir, binary);
|
|
517
|
+
if (node_fs_1.default.existsSync(candidate)) {
|
|
518
|
+
return resolveRealPath(candidate);
|
|
519
|
+
}
|
|
520
|
+
if (process.platform === "win32") {
|
|
521
|
+
const executable = `${candidate}.exe`;
|
|
522
|
+
if (node_fs_1.default.existsSync(executable)) {
|
|
523
|
+
return resolveRealPath(executable);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return binary;
|
|
528
|
+
}
|
|
529
|
+
function resolveRealPath(location) {
|
|
530
|
+
try {
|
|
531
|
+
return node_fs_1.default.realpathSync(location);
|
|
532
|
+
}
|
|
533
|
+
catch {
|
|
534
|
+
return location;
|
|
535
|
+
}
|
|
388
536
|
}
|
|
389
537
|
//# sourceMappingURL=buildSourcePlugin.js.map
|