Make tsserver and typingsInstaller thin wrappers around public API (#55326)

This commit is contained in:
Jake Bailey 2024-03-15 13:25:26 -07:00 committed by GitHub
parent b009837298
commit aeddd65ab8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 147 additions and 214 deletions

View File

@ -184,6 +184,7 @@ async function runDtsBundler(entrypoint, output) {
* @typedef BundlerTaskOptions
* @property {boolean} [exportIsTsObject]
* @property {boolean} [treeShaking]
* @property {boolean} [usePublicAPI]
* @property {() => void} [onWatchRebuild]
*/
function createBundler(entrypoint, outfile, taskOptions = {}) {
@ -208,6 +209,19 @@ function createBundler(entrypoint, outfile, taskOptions = {}) {
// legalComments: "none", // If we add copyright headers to the source files, uncomment.
};
if (taskOptions.usePublicAPI) {
options.external = ["./typescript.js"];
options.plugins = options.plugins || [];
options.plugins.push({
name: "remap-typescript-to-require",
setup(build) {
build.onLoad({ filter: /src[\\/]typescript[\\/]typescript\.ts$/ }, () => {
return { contents: `export * from "./typescript.js"` };
});
},
});
}
if (taskOptions.exportIsTsObject) {
// Monaco bundles us as ESM by wrapping our code with something that defines module.exports
// but then does not use it, instead using the `ts` variable. Ensure that if we think we're CJS
@ -235,7 +249,8 @@ function createBundler(entrypoint, outfile, taskOptions = {}) {
const toCommonJsRegExp = /var __toCommonJS .*/;
const toCommonJsRegExpReplacement = "var __toCommonJS = (mod) => (__copyProps, mod); // Modified helper to skip setting __esModule.";
options.plugins = [
options.plugins = options.plugins || [];
options.plugins.push(
{
name: "post-process",
setup: build => {
@ -252,7 +267,7 @@ function createBundler(entrypoint, outfile, taskOptions = {}) {
});
},
},
];
);
}
return options;
@ -422,7 +437,8 @@ const { main: tsserver, watch: watchTsserver } = entrypointBuildTask({
srcEntrypoint: "./src/tsserver/server.ts",
builtEntrypoint: "./built/local/tsserver/server.js",
output: "./built/local/tsserver.js",
mainDeps: [generateLibs],
mainDeps: [generateLibs, services],
bundlerOptions: { usePublicAPI: true },
});
export { tsserver, watchTsserver };
@ -572,6 +588,8 @@ const { main: typingsInstaller, watch: watchTypingsInstaller } = entrypointBuild
srcEntrypoint: "./src/typingsInstaller/nodeTypingsInstaller.ts",
builtEntrypoint: "./built/local/typingsInstaller/nodeTypingsInstaller.js",
output: "./built/local/typingsInstaller.js",
mainDeps: [services],
bundlerOptions: { usePublicAPI: true },
});
const { main: watchGuard, watch: watchWatchGuard } = entrypointBuildTask({

View File

@ -1,6 +0,0 @@
/* Generated file to emulate the ts.server namespace. */
export * from "../../jsTyping/_namespaces/ts.server";
export * from "../../server/_namespaces/ts.server";
export * from "../nodeServer";
export * from "../common";

View File

@ -1,8 +1 @@
/* Generated file to emulate the ts namespace. */
export * from "../../compiler/_namespaces/ts";
export * from "../../services/_namespaces/ts";
export * from "../../jsTyping/_namespaces/ts";
export * from "../../server/_namespaces/ts";
import * as server from "./ts.server";
export { server };
export * from "../../typescript/typescript";

View File

@ -1,20 +1,12 @@
import {
LanguageServiceMode,
} from "./_namespaces/ts";
import {
Logger,
LogLevel,
ServerCancellationToken,
SessionOptions,
} from "./_namespaces/ts.server";
import * as ts from "./_namespaces/ts";
/** @internal */
export function getLogLevel(level: string | undefined) {
if (level) {
const l = level.toLowerCase();
for (const name in LogLevel) {
for (const name in ts.server.LogLevel) {
if (isNaN(+name) && l === name.toLowerCase()) {
return LogLevel[name] as any as LogLevel;
return ts.server.LogLevel[name] as any as ts.server.LogLevel;
}
}
}
@ -23,23 +15,23 @@ export function getLogLevel(level: string | undefined) {
/** @internal */
export interface StartSessionOptions {
globalPlugins: SessionOptions["globalPlugins"];
pluginProbeLocations: SessionOptions["pluginProbeLocations"];
allowLocalPluginLoads: SessionOptions["allowLocalPluginLoads"];
useSingleInferredProject: SessionOptions["useSingleInferredProject"];
useInferredProjectPerProjectRoot: SessionOptions["useInferredProjectPerProjectRoot"];
suppressDiagnosticEvents: SessionOptions["suppressDiagnosticEvents"];
noGetErrOnBackgroundUpdate: SessionOptions["noGetErrOnBackgroundUpdate"];
canUseWatchEvents: SessionOptions["canUseWatchEvents"];
serverMode: SessionOptions["serverMode"];
globalPlugins: ts.server.SessionOptions["globalPlugins"];
pluginProbeLocations: ts.server.SessionOptions["pluginProbeLocations"];
allowLocalPluginLoads: ts.server.SessionOptions["allowLocalPluginLoads"];
useSingleInferredProject: ts.server.SessionOptions["useSingleInferredProject"];
useInferredProjectPerProjectRoot: ts.server.SessionOptions["useInferredProjectPerProjectRoot"];
suppressDiagnosticEvents: ts.server.SessionOptions["suppressDiagnosticEvents"];
noGetErrOnBackgroundUpdate: ts.server.SessionOptions["noGetErrOnBackgroundUpdate"];
canUseWatchEvents: ts.server.SessionOptions["canUseWatchEvents"];
serverMode: ts.server.SessionOptions["serverMode"];
}
/** @internal */
export interface StartInput {
args: readonly string[];
logger: Logger;
cancellationToken: ServerCancellationToken;
serverMode: LanguageServiceMode | undefined;
logger: ts.server.Logger;
cancellationToken: ts.server.ServerCancellationToken;
serverMode: ts.LanguageServiceMode | undefined;
unknownServerMode?: string;
startSession: (option: StartSessionOptions, logger: Logger, cancellationToken: ServerCancellationToken) => void;
startSession: (option: StartSessionOptions, logger: ts.server.Logger, cancellationToken: ts.server.ServerCancellationToken) => void;
}

View File

@ -1,5 +1,3 @@
import * as protocol from "../server/protocol";
import * as ts from "./_namespaces/ts";
import {
CharacterCodes,
combinePaths,
@ -26,32 +24,16 @@ import {
versionMajorMinor,
WatchOptions,
} from "./_namespaces/ts";
import * as ts from "./_namespaces/ts";
import {
Arguments,
Event,
findArgument,
formatMessage,
getLogLevel,
hasArgument,
indent,
Logger,
LogLevel,
Msg,
nowString,
nullCancellationToken,
ServerCancellationToken,
ServerHost,
Session,
StartInput,
StartSessionOptions,
stringifyIndented,
toEvent,
TypingsInstallerAdapter,
} from "./_namespaces/ts.server";
} from "./common";
interface LogOptions {
file?: string;
detailLevel?: LogLevel;
detailLevel?: ts.server.LogLevel;
traceToConsole?: boolean;
logToFile?: boolean;
}
@ -92,7 +74,7 @@ function parseLoggingEnvironmentString(logEnvStr: string | undefined): LogOption
break;
case "-level":
const level = getLogLevel(value);
logEnv.detailLevel = level !== undefined ? level : LogLevel.normal;
logEnv.detailLevel = level !== undefined ? level : ts.server.LogLevel.normal;
break;
case "-traceToConsole":
logEnv.traceToConsole = value.toLowerCase() === "true";
@ -124,7 +106,7 @@ function parseLoggingEnvironmentString(logEnvStr: string | undefined): LogOption
}
function parseServerMode(): LanguageServiceMode | string | undefined {
const mode = findArgument("--serverMode");
const mode = ts.server.findArgument("--serverMode");
if (!mode) return undefined;
switch (mode.toLowerCase()) {
@ -141,7 +123,7 @@ function parseServerMode(): LanguageServiceMode | string | undefined {
/** @internal */
export function initializeNodeSystem(): StartInput {
const sys = Debug.checkDefined(ts.sys) as ServerHost;
const sys = Debug.checkDefined(ts.sys) as ts.server.ServerHost;
const childProcess: {
execFileSync(file: string, args: string[], options: { stdio: "ignore"; env: MapLike<string>; }): string | Buffer;
} = require("child_process");
@ -186,7 +168,7 @@ export function initializeNodeSystem(): StartInput {
constructor(
private readonly logFilename: string,
private readonly traceToConsole: boolean,
private readonly level: LogLevel,
private readonly level: ts.server.LogLevel,
) {
if (this.logFilename) {
try {
@ -209,13 +191,13 @@ export function initializeNodeSystem(): StartInput {
return this.logFilename;
}
perftrc(s: string) {
this.msg(s, Msg.Perf);
this.msg(s, ts.server.Msg.Perf);
}
info(s: string) {
this.msg(s, Msg.Info);
this.msg(s, ts.server.Msg.Info);
}
err(s: string) {
this.msg(s, Msg.Err);
this.msg(s, ts.server.Msg.Err);
}
startGroup() {
this.inGroup = true;
@ -227,15 +209,15 @@ export function initializeNodeSystem(): StartInput {
loggingEnabled() {
return !!this.logFilename || this.traceToConsole;
}
hasLevel(level: LogLevel) {
hasLevel(level: ts.server.LogLevel) {
return this.loggingEnabled() && this.level >= level;
}
msg(s: string, type: Msg = Msg.Err) {
msg(s: string, type: ts.server.Msg = ts.server.Msg.Err) {
switch (type) {
case Msg.Info:
case ts.server.Msg.Info:
perfLogger?.logInfoEvent(s);
break;
case Msg.Perf:
case ts.server.Msg.Perf:
perfLogger?.logPerfEvent(s);
break;
default: // Msg.Err
@ -245,7 +227,7 @@ export function initializeNodeSystem(): StartInput {
if (!this.canWrite()) return;
s = `[${nowString()}] ${s}\n`;
s = `[${ts.server.nowString()}] ${s}\n`;
if (!this.inGroup || this.firstInGroup) {
const prefix = Logger.padStringRight(type + " " + this.seq.toString(), " ");
s = prefix + s;
@ -258,7 +240,7 @@ export function initializeNodeSystem(): StartInput {
protected canWrite() {
return this.fd >= 0 || this.traceToConsole;
}
protected write(s: string, _type: Msg) {
protected write(s: string, _type: ts.server.Msg) {
if (this.fd >= 0) {
const buf = sys.bufferFrom!(s);
// eslint-disable-next-line no-null/no-null
@ -273,7 +255,7 @@ export function initializeNodeSystem(): StartInput {
const libDirectory = getDirectoryPath(normalizePath(sys.getExecutingFilePath()));
const useWatchGuard = process.platform === "win32";
const originalWatchDirectory: ServerHost["watchDirectory"] = sys.watchDirectory.bind(sys);
const originalWatchDirectory: ts.server.ServerHost["watchDirectory"] = sys.watchDirectory.bind(sys);
const logger = createLogger();
// enable deprecation logging
@ -282,10 +264,10 @@ export function initializeNodeSystem(): StartInput {
switch (level) {
case ts.LogLevel.Error:
case ts.LogLevel.Warning:
return logger.msg(s, Msg.Err);
return logger.msg(s, ts.server.Msg.Err);
case ts.LogLevel.Info:
case ts.LogLevel.Verbose:
return logger.msg(s, Msg.Info);
return logger.msg(s, ts.server.Msg.Info);
}
},
};
@ -300,23 +282,23 @@ export function initializeNodeSystem(): StartInput {
const cacheKey = extractWatchDirectoryCacheKey(path, currentDrive);
let status = cacheKey && statusCache.get(cacheKey);
if (status === undefined) {
if (logger.hasLevel(LogLevel.verbose)) {
if (logger.hasLevel(ts.server.LogLevel.verbose)) {
logger.info(`${cacheKey} for path ${path} not found in cache...`);
}
try {
const args = [combinePaths(libDirectory, "watchGuard.js"), path];
if (logger.hasLevel(LogLevel.verbose)) {
logger.info(`Starting ${process.execPath} with args:${stringifyIndented(args)}`);
if (logger.hasLevel(ts.server.LogLevel.verbose)) {
logger.info(`Starting ${process.execPath} with args:${ts.server.stringifyIndented(args)}`);
}
childProcess.execFileSync(process.execPath, args, { stdio: "ignore", env: { ELECTRON_RUN_AS_NODE: "1" } });
status = true;
if (logger.hasLevel(LogLevel.verbose)) {
if (logger.hasLevel(ts.server.LogLevel.verbose)) {
logger.info(`WatchGuard for path ${path} returned: OK`);
}
}
catch (e) {
status = false;
if (logger.hasLevel(LogLevel.verbose)) {
if (logger.hasLevel(ts.server.LogLevel.verbose)) {
logger.info(`WatchGuard for path ${path} returned: ${e.message}`);
}
}
@ -324,7 +306,7 @@ export function initializeNodeSystem(): StartInput {
statusCache.set(cacheKey, status);
}
}
else if (logger.hasLevel(LogLevel.verbose)) {
else if (logger.hasLevel(ts.server.LogLevel.verbose)) {
logger.info(`watchDirectory for ${path} uses cached drive information.`);
}
if (status) {
@ -355,16 +337,16 @@ export function initializeNodeSystem(): StartInput {
sys.gc = () => global.gc?.();
}
let cancellationToken: ServerCancellationToken;
let cancellationToken: ts.server.ServerCancellationToken;
try {
const factory = require("./cancellationToken");
cancellationToken = factory(sys.args);
}
catch (e) {
cancellationToken = nullCancellationToken;
cancellationToken = ts.server.nullCancellationToken;
}
const localeStr = findArgument("--locale");
const localeStr = ts.server.findArgument("--locale");
if (localeStr) {
validateLocaleAndSetLanguage(localeStr, sys);
}
@ -387,8 +369,8 @@ export function initializeNodeSystem(): StartInput {
// TSS_LOG "{ level: "normal | verbose | terse", file?: string}"
function createLogger() {
const cmdLineLogFileName = findArgument("--logFile");
const cmdLineVerbosity = getLogLevel(findArgument("--logVerbosity"));
const cmdLineLogFileName = ts.server.findArgument("--logFile");
const cmdLineVerbosity = getLogLevel(ts.server.findArgument("--logVerbosity"));
const envLogOptions = parseLoggingEnvironmentString(process.env.TSS_LOG);
const unsubstitutedLogFileName = cmdLineLogFileName
@ -469,7 +451,7 @@ function parseEventPort(eventPortStr: string | undefined) {
const eventPort = eventPortStr === undefined ? undefined : parseInt(eventPortStr);
return eventPort !== undefined && !isNaN(eventPort) ? eventPort : undefined;
}
function startNodeSession(options: StartSessionOptions, logger: Logger, cancellationToken: ServerCancellationToken) {
function startNodeSession(options: StartSessionOptions, logger: ts.server.Logger, cancellationToken: ts.server.ServerCancellationToken) {
const childProcess: {
fork(modulePath: string, args: string[], options?: { execArgv: string[]; env?: MapLike<string>; }): NodeChildProcess;
} = require("child_process");
@ -493,7 +475,7 @@ function startNodeSession(options: StartSessionOptions, logger: Logger, cancella
terminal: false,
});
class NodeTypingsInstallerAdapter extends TypingsInstallerAdapter {
class NodeTypingsInstallerAdapter extends ts.server.TypingsInstallerAdapter {
protected override installer!: NodeChildProcess;
// This number is essentially arbitrary. Processing more than one typings request
// at a time makes sense, but having too many in the pipe results in a hang
@ -504,14 +486,14 @@ function startNodeSession(options: StartSessionOptions, logger: Logger, cancella
constructor(
telemetryEnabled: boolean,
logger: Logger,
host: ServerHost,
logger: ts.server.Logger,
host: ts.server.ServerHost,
globalTypingsCacheLocation: string,
readonly typingSafeListLocation: string,
readonly typesMapLocation: string,
private readonly npmLocation: string | undefined,
private readonly validateDefaultNpmLocation: boolean,
event: Event,
event: ts.server.Event,
) {
super(
telemetryEnabled,
@ -524,28 +506,28 @@ function startNodeSession(options: StartSessionOptions, logger: Logger, cancella
}
createInstallerProcess() {
if (this.logger.hasLevel(LogLevel.requestTime)) {
if (this.logger.hasLevel(ts.server.LogLevel.requestTime)) {
this.logger.info("Binding...");
}
const args: string[] = [Arguments.GlobalCacheLocation, this.globalTypingsCacheLocation];
const args: string[] = [ts.server.Arguments.GlobalCacheLocation, this.globalTypingsCacheLocation];
if (this.telemetryEnabled) {
args.push(Arguments.EnableTelemetry);
args.push(ts.server.Arguments.EnableTelemetry);
}
if (this.logger.loggingEnabled() && this.logger.getLogFileName()) {
args.push(Arguments.LogFile, combinePaths(getDirectoryPath(normalizeSlashes(this.logger.getLogFileName()!)), `ti-${process.pid}.log`));
args.push(ts.server.Arguments.LogFile, combinePaths(getDirectoryPath(normalizeSlashes(this.logger.getLogFileName()!)), `ti-${process.pid}.log`));
}
if (this.typingSafeListLocation) {
args.push(Arguments.TypingSafeListLocation, this.typingSafeListLocation);
args.push(ts.server.Arguments.TypingSafeListLocation, this.typingSafeListLocation);
}
if (this.typesMapLocation) {
args.push(Arguments.TypesMapLocation, this.typesMapLocation);
args.push(ts.server.Arguments.TypesMapLocation, this.typesMapLocation);
}
if (this.npmLocation) {
args.push(Arguments.NpmLocation, this.npmLocation);
args.push(ts.server.Arguments.NpmLocation, this.npmLocation);
}
if (this.validateDefaultNpmLocation) {
args.push(Arguments.ValidateDefaultNpmLocation);
args.push(ts.server.Arguments.ValidateDefaultNpmLocation);
}
const execArgv: string[] = [];
@ -579,7 +561,7 @@ function startNodeSession(options: StartSessionOptions, logger: Logger, cancella
}
}
class IOSession extends Session {
class IOSession extends ts.server.Session {
private eventPort: number | undefined;
private eventSocket: NodeSocket | undefined;
private socketEventQueue: { body: any; eventName: string; }[] | undefined;
@ -591,7 +573,7 @@ function startNodeSession(options: StartSessionOptions, logger: Logger, cancella
this.event(body, eventName);
};
const host = sys as ServerHost;
const host = sys as ts.server.ServerHost;
const typingsInstaller = disableAutomaticTypingAcquisition
? undefined
@ -631,7 +613,7 @@ function startNodeSession(options: StartSessionOptions, logger: Logger, cancella
if (this.canUseEvents && this.eventPort) {
if (!this.eventSocket) {
if (this.logger.hasLevel(LogLevel.verbose)) {
if (this.logger.hasLevel(ts.server.LogLevel.verbose)) {
this.logger.info(`eventPort: event "${eventName}" queued, but socket not yet initialized`);
}
(this.socketEventQueue || (this.socketEventQueue = [])).push({ body, eventName });
@ -648,7 +630,7 @@ function startNodeSession(options: StartSessionOptions, logger: Logger, cancella
}
private writeToEventSocket(body: object, eventName: string): void {
this.eventSocket!.write(formatMessage(toEvent(eventName, body), this.logger, this.byteLength, this.host.newLine), "utf8");
this.eventSocket!.write(ts.server.formatMessage(ts.server.toEvent(eventName, body), this.logger, this.byteLength, this.host.newLine), "utf8");
}
override exit() {
@ -671,18 +653,18 @@ function startNodeSession(options: StartSessionOptions, logger: Logger, cancella
}
class IpcIOSession extends IOSession {
protected override writeMessage(msg: protocol.Message): void {
const verboseLogging = logger.hasLevel(LogLevel.verbose);
protected override writeMessage(msg: ts.server.protocol.Message): void {
const verboseLogging = logger.hasLevel(ts.server.LogLevel.verbose);
if (verboseLogging) {
const json = JSON.stringify(msg);
logger.info(`${msg.type}:${indent(json)}`);
logger.info(`${msg.type}:${ts.server.indent(json)}`);
}
process.send!(msg);
}
protected override parseMessage(message: any): protocol.Request {
return message as protocol.Request;
protected override parseMessage(message: any): ts.server.protocol.Request {
return message as ts.server.protocol.Request;
}
protected override toStringMessage(message: any) {
@ -700,15 +682,15 @@ function startNodeSession(options: StartSessionOptions, logger: Logger, cancella
}
}
const eventPort: number | undefined = parseEventPort(findArgument("--eventPort"));
const typingSafeListLocation = findArgument(Arguments.TypingSafeListLocation)!; // TODO: GH#18217
const typesMapLocation = findArgument(Arguments.TypesMapLocation) || combinePaths(getDirectoryPath(sys.getExecutingFilePath()), "typesMap.json");
const npmLocation = findArgument(Arguments.NpmLocation);
const validateDefaultNpmLocation = hasArgument(Arguments.ValidateDefaultNpmLocation);
const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition");
const useNodeIpc = hasArgument("--useNodeIpc");
const telemetryEnabled = hasArgument(Arguments.EnableTelemetry);
const commandLineTraceDir = findArgument("--traceDirectory");
const eventPort: number | undefined = parseEventPort(ts.server.findArgument("--eventPort"));
const typingSafeListLocation = ts.server.findArgument(ts.server.Arguments.TypingSafeListLocation)!; // TODO: GH#18217
const typesMapLocation = ts.server.findArgument(ts.server.Arguments.TypesMapLocation) || combinePaths(getDirectoryPath(sys.getExecutingFilePath()), "typesMap.json");
const npmLocation = ts.server.findArgument(ts.server.Arguments.NpmLocation);
const validateDefaultNpmLocation = ts.server.hasArgument(ts.server.Arguments.ValidateDefaultNpmLocation);
const disableAutomaticTypingAcquisition = ts.server.hasArgument("--disableAutomaticTypingAcquisition");
const useNodeIpc = ts.server.hasArgument("--useNodeIpc");
const telemetryEnabled = ts.server.hasArgument(ts.server.Arguments.EnableTelemetry);
const commandLineTraceDir = ts.server.findArgument("--traceDirectory");
const traceDir = commandLineTraceDir
? stripQuotes(commandLineTraceDir)
: process.env.TSS_TRACE;

View File

@ -1,63 +1,54 @@
import * as ts from "./_namespaces/ts";
import {
Debug,
setStackTraceLimit,
sys,
version,
} from "./_namespaces/ts";
import {
emptyArray,
findArgument,
hasArgument,
initializeNodeSystem,
Msg,
StartInput,
} from "./_namespaces/ts.server";
export * from "./_namespaces/ts";
} from "./common";
import {
initializeNodeSystem,
} from "./nodeServer";
function findArgumentStringArray(argName: string): readonly string[] {
const arg = findArgument(argName);
const arg = ts.server.findArgument(argName);
if (arg === undefined) {
return emptyArray;
return ts.emptyArray;
}
return arg.split(",").filter(name => name !== "");
}
function start({ args, logger, cancellationToken, serverMode, unknownServerMode, startSession: startServer }: StartInput, platform: string) {
logger.info(`Starting TS Server`);
logger.info(`Version: ${version}`);
logger.info(`Version: ${ts.version}`);
logger.info(`Arguments: ${args.join(" ")}`);
logger.info(`Platform: ${platform} NodeVersion: ${process.version} CaseSensitive: ${sys.useCaseSensitiveFileNames}`);
logger.info(`Platform: ${platform} NodeVersion: ${process.version} CaseSensitive: ${ts.sys.useCaseSensitiveFileNames}`);
logger.info(`ServerMode: ${serverMode} hasUnknownServerMode: ${unknownServerMode}`);
setStackTraceLimit();
ts.setStackTraceLimit();
if (Debug.isDebugging) {
Debug.enableDebugInfo();
if (ts.Debug.isDebugging) {
ts.Debug.enableDebugInfo();
}
if (sys.tryEnableSourceMapsForHost && /^development$/i.test(sys.getEnvironmentVariable("NODE_ENV"))) {
sys.tryEnableSourceMapsForHost();
if (ts.sys.tryEnableSourceMapsForHost && /^development$/i.test(ts.sys.getEnvironmentVariable("NODE_ENV"))) {
ts.sys.tryEnableSourceMapsForHost();
}
// Overwrites the current console messages to instead write to
// the log. This is so that language service plugins which use
// console.log don't break the message passing between tsserver
// and the client
console.log = (...args) => logger.msg(args.length === 1 ? args[0] : args.join(", "), Msg.Info);
console.warn = (...args) => logger.msg(args.length === 1 ? args[0] : args.join(", "), Msg.Err);
console.error = (...args) => logger.msg(args.length === 1 ? args[0] : args.join(", "), Msg.Err);
console.log = (...args) => logger.msg(args.length === 1 ? args[0] : args.join(", "), ts.server.Msg.Info);
console.warn = (...args) => logger.msg(args.length === 1 ? args[0] : args.join(", "), ts.server.Msg.Err);
console.error = (...args) => logger.msg(args.length === 1 ? args[0] : args.join(", "), ts.server.Msg.Err);
startServer(
{
globalPlugins: findArgumentStringArray("--globalPlugins"),
pluginProbeLocations: findArgumentStringArray("--pluginProbeLocations"),
allowLocalPluginLoads: hasArgument("--allowLocalPluginLoads"),
useSingleInferredProject: hasArgument("--useSingleInferredProject"),
useInferredProjectPerProjectRoot: hasArgument("--useInferredProjectPerProjectRoot"),
suppressDiagnosticEvents: hasArgument("--suppressDiagnosticEvents"),
noGetErrOnBackgroundUpdate: hasArgument("--noGetErrOnBackgroundUpdate"),
canUseWatchEvents: hasArgument("--canUseWatchEvents"),
allowLocalPluginLoads: ts.server.hasArgument("--allowLocalPluginLoads"),
useSingleInferredProject: ts.server.hasArgument("--useSingleInferredProject"),
useInferredProjectPerProjectRoot: ts.server.hasArgument("--useInferredProjectPerProjectRoot"),
suppressDiagnosticEvents: ts.server.hasArgument("--suppressDiagnosticEvents"),
noGetErrOnBackgroundUpdate: ts.server.hasArgument("--noGetErrOnBackgroundUpdate"),
canUseWatchEvents: ts.server.hasArgument("--canUseWatchEvents"),
serverMode,
},
logger,
@ -65,5 +56,5 @@ function start({ args, logger, cancellationToken, serverMode, unknownServerMode,
);
}
setStackTraceLimit();
ts.setStackTraceLimit();
start(initializeNodeSystem(), require("os").platform());

View File

@ -7,10 +7,7 @@
]
},
"references": [
{ "path": "../compiler" },
{ "path": "../services" },
{ "path": "../jsTyping" },
{ "path": "../server" }
{ "path": "../typescript" }
],
"include": ["**/*"]
}

View File

@ -1,6 +0,0 @@
/* Generated file to emulate the ts.server namespace. */
export * from "../../jsTyping/_namespaces/ts.server";
export * from "../../typingsInstallerCore/_namespaces/ts.server";
import * as typingsInstaller from "./ts.server.typingsInstaller";
export { typingsInstaller };

View File

@ -1,4 +0,0 @@
/* Generated file to emulate the ts.server.typingsInstaller namespace. */
export * from "../../typingsInstallerCore/_namespaces/ts.server.typingsInstaller";
export * from "../nodeTypingsInstaller";

View File

@ -1,7 +1 @@
/* Generated file to emulate the ts namespace. */
export * from "../../compiler/_namespaces/ts";
export * from "../../jsTyping/_namespaces/ts";
export * from "../../typingsInstallerCore/_namespaces/ts";
import * as server from "./ts.server";
export { server };
export * from "../../typescript/typescript";

View File

@ -12,25 +12,9 @@ import {
toPath,
version,
} from "./_namespaces/ts";
import {
Arguments,
findArgument,
hasArgument,
InitializationFailedResponse,
InstallTypingHost,
nowString,
stringifyIndented,
TypingInstallerRequestUnion,
TypingInstallerResponseUnion,
} from "./_namespaces/ts.server";
import {
installNpmPackages,
Log,
RequestCompletedAction,
TypingsInstaller,
} from "./_namespaces/ts.server.typingsInstaller";
import * as ts from "./_namespaces/ts";
class FileLog implements Log {
class FileLog implements ts.server.typingsInstaller.Log {
constructor(private logFile: string | undefined) {
}
@ -41,7 +25,7 @@ class FileLog implements Log {
if (typeof this.logFile !== "string") return;
try {
fs.appendFileSync(this.logFile, `[${nowString()}] ${text}${sys.newLine}`);
fs.appendFileSync(this.logFile, `[${ts.server.nowString()}] ${text}${sys.newLine}`);
}
catch (e) {
this.logFile = undefined;
@ -50,7 +34,7 @@ class FileLog implements Log {
}
/** Used if `--npmLocation` is not passed. */
function getDefaultNPMLocation(processName: string, validateDefaultNpmLocation: boolean, host: InstallTypingHost): string {
function getDefaultNPMLocation(processName: string, validateDefaultNpmLocation: boolean, host: ts.server.InstallTypingHost): string {
if (path.basename(processName).indexOf("node") === 0) {
const npmPath = path.join(path.dirname(process.argv[0]), "npm");
if (!validateDefaultNpmLocation) {
@ -67,7 +51,7 @@ interface TypesRegistryFile {
entries: MapLike<MapLike<string>>;
}
function loadTypesRegistryFile(typesRegistryFilePath: string, host: InstallTypingHost, log: Log): Map<string, MapLike<string>> {
function loadTypesRegistryFile(typesRegistryFilePath: string, host: ts.server.InstallTypingHost, log: ts.server.typingsInstaller.Log): Map<string, MapLike<string>> {
if (!host.fileExists(typesRegistryFilePath)) {
if (log.isEnabled()) {
log.writeLine(`Types registry file '${typesRegistryFilePath}' does not exist`);
@ -97,14 +81,14 @@ interface ExecSyncOptions {
}
type ExecSync = (command: string, options: ExecSyncOptions) => string;
export class NodeTypingsInstaller extends TypingsInstaller {
export class NodeTypingsInstaller extends ts.server.typingsInstaller.TypingsInstaller {
private readonly nodeExecSync: ExecSync;
private readonly npmPath: string;
readonly typesRegistry: Map<string, MapLike<string>>;
private delayedInitializationError: InitializationFailedResponse | undefined;
private delayedInitializationError: ts.server.InitializationFailedResponse | undefined;
constructor(globalTypingsCacheLocation: string, typingSafeListLocation: string, typesMapLocation: string, npmLocation: string | undefined, validateDefaultNpmLocation: boolean, throttleLimit: number, log: Log) {
constructor(globalTypingsCacheLocation: string, typingSafeListLocation: string, typesMapLocation: string, npmLocation: string | undefined, validateDefaultNpmLocation: boolean, throttleLimit: number, log: ts.server.typingsInstaller.Log) {
const libDirectory = getDirectoryPath(normalizePath(sys.getExecutingFilePath()));
super(
sys,
@ -122,7 +106,7 @@ export class NodeTypingsInstaller extends TypingsInstaller {
}
if (this.log.isEnabled()) {
this.log.writeLine(`Process id: ${process.pid}`);
this.log.writeLine(`NPM location: ${this.npmPath} (explicit '${Arguments.NpmLocation}' ${npmLocation === undefined ? "not " : ""} provided)`);
this.log.writeLine(`NPM location: ${this.npmPath} (explicit '${ts.server.Arguments.NpmLocation}' ${npmLocation === undefined ? "not " : ""} provided)`);
this.log.writeLine(`validateDefaultNpmLocation: ${validateDefaultNpmLocation}`);
}
({ execSync: this.nodeExecSync } = require("child_process"));
@ -153,7 +137,7 @@ export class NodeTypingsInstaller extends TypingsInstaller {
this.typesRegistry = loadTypesRegistryFile(getTypesRegistryFileLocation(globalTypingsCacheLocation), this.installTypingHost, this.log);
}
override handleRequest(req: TypingInstallerRequestUnion) {
override handleRequest(req: ts.server.TypingInstallerRequestUnion) {
if (this.delayedInitializationError) {
// report initializationFailed error
this.sendResponse(this.delayedInitializationError);
@ -162,9 +146,9 @@ export class NodeTypingsInstaller extends TypingsInstaller {
super.handleRequest(req);
}
protected sendResponse(response: TypingInstallerResponseUnion) {
protected sendResponse(response: ts.server.TypingInstallerResponseUnion) {
if (this.log.isEnabled()) {
this.log.writeLine(`Sending response:${stringifyIndented(response)}`);
this.log.writeLine(`Sending response:${ts.server.stringifyIndented(response)}`);
}
process.send!(response); // TODO: GH#18217
if (this.log.isEnabled()) {
@ -172,12 +156,12 @@ export class NodeTypingsInstaller extends TypingsInstaller {
}
}
protected installWorker(requestId: number, packageNames: string[], cwd: string, onRequestCompleted: RequestCompletedAction): void {
protected installWorker(requestId: number, packageNames: string[], cwd: string, onRequestCompleted: ts.server.typingsInstaller.RequestCompletedAction): void {
if (this.log.isEnabled()) {
this.log.writeLine(`#${requestId} with cwd: ${cwd} arguments: ${JSON.stringify(packageNames)}`);
}
const start = Date.now();
const hasError = installNpmPackages(this.npmPath, version, packageNames, command => this.execSyncAndLog(command, { cwd }));
const hasError = ts.server.typingsInstaller.installNpmPackages(this.npmPath, version, packageNames, command => this.execSyncAndLog(command, { cwd }));
if (this.log.isEnabled()) {
this.log.writeLine(`npm install #${requestId} took: ${Date.now() - start} ms`);
}
@ -204,12 +188,12 @@ export class NodeTypingsInstaller extends TypingsInstaller {
}
}
const logFilePath = findArgument(Arguments.LogFile);
const globalTypingsCacheLocation = findArgument(Arguments.GlobalCacheLocation);
const typingSafeListLocation = findArgument(Arguments.TypingSafeListLocation);
const typesMapLocation = findArgument(Arguments.TypesMapLocation);
const npmLocation = findArgument(Arguments.NpmLocation);
const validateDefaultNpmLocation = hasArgument(Arguments.ValidateDefaultNpmLocation);
const logFilePath = ts.server.findArgument(ts.server.Arguments.LogFile);
const globalTypingsCacheLocation = ts.server.findArgument(ts.server.Arguments.GlobalCacheLocation);
const typingSafeListLocation = ts.server.findArgument(ts.server.Arguments.TypingSafeListLocation);
const typesMapLocation = ts.server.findArgument(ts.server.Arguments.TypesMapLocation);
const npmLocation = ts.server.findArgument(ts.server.Arguments.NpmLocation);
const validateDefaultNpmLocation = ts.server.hasArgument(ts.server.Arguments.ValidateDefaultNpmLocation);
const log = new FileLog(logFilePath);
if (log.isEnabled()) {
@ -224,7 +208,7 @@ process.on("disconnect", () => {
process.exit(0);
});
let installer: NodeTypingsInstaller | undefined;
process.on("message", (req: TypingInstallerRequestUnion) => {
process.on("message", (req: ts.server.TypingInstallerRequestUnion) => {
installer ??= new NodeTypingsInstaller(globalTypingsCacheLocation!, typingSafeListLocation!, typesMapLocation!, npmLocation, validateDefaultNpmLocation, /*throttleLimit*/ 5, log); // TODO: GH#18217
installer.handleRequest(req);
});

View File

@ -6,9 +6,7 @@
]
},
"references": [
{ "path": "../compiler" },
{ "path": "../jsTyping" },
{ "path": "../typingsInstallerCore" }
{ "path": "../typescript" }
],
"include": ["**/*"]
}