Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions packages/compiler/src/server/compile-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { deepClone, distinctArray } from "../utils/misc.js";
import { getLocationInYamlScript } from "../yaml/diagnostics.js";
import { parseYaml } from "../yaml/parser.js";
import { ClientConfigProvider } from "./client-config-provider.js";
import { serverOptions } from "./constants.js";
import { DebugAreas, isDebugEnabled, serverOptions } from "./constants.js";
import { resolveEntrypointFile } from "./entrypoint-resolver.js";
import { FileService } from "./file-service.js";
import { FileSystemCache } from "./file-system-cache.js";
Expand Down Expand Up @@ -90,6 +90,7 @@ export function createCompileService({
const eventListeners = new Map<string, (...args: unknown[]) => void | Promise<void>>();
const compileManager = new ServerCompileManager(updateManager, compilerHost, log);
let configFilePath: string | undefined;
const logDebug = isDebugEnabled(DebugAreas.COMPILE_CONFIG) ? log : () => {};

return { compile, getScript, on, notifyChange, getMainFileForDocument };

Expand Down Expand Up @@ -129,15 +130,15 @@ export function createCompileService({
}
const mainFile = await getMainFileForDocument(path);
if (mainFile === undefined) {
log({ level: "debug", message: `failed to resolve main file for ${path}` });
logDebug({ level: "debug", message: `failed to resolve main file for ${path}` });
return undefined;
}
if (!mainFile.endsWith(".tsp")) {
return undefined;
}
const config = await getConfig(mainFile);
configFilePath = config.filename;
log({ level: "debug", message: `config resolved`, detail: config });
logDebug({ level: "debug", message: `config resolved`, detail: config });
const [optionsFromConfig, _] = resolveOptionsFromConfig(config, {
cwd: getDirectoryPath(path),
});
Expand Down Expand Up @@ -217,7 +218,7 @@ export function createCompileService({
) {
// If the file that changed wasn't imported by anything from the main
// file, retry using the file itself as the main file.
log({
logDebug({
level: "debug",
message: `target file was not included in compiling, try to compile ${path} as main file directly`,
});
Expand Down Expand Up @@ -246,7 +247,7 @@ export function createCompileService({
const [yamlScript] = parseYaml(await serverHost.compilerHost.readFile(configFilePath));
const target = getLocationInYamlScript(yamlScript, ["emit", emitterName], "key");
if (target.pos === 0) {
log({
logDebug({
level: "debug",
message: `Unexpected situation, can't find emitter '${emitterName}' in config file '${configFilePath}'`,
});
Expand Down Expand Up @@ -286,7 +287,7 @@ export function createCompileService({
const lookupDir = entrypointStat.isDirectory() ? mainFile : getDirectoryPath(mainFile);
const configPath = await findTypeSpecConfigPath(compilerHost, lookupDir, true);
if (!configPath) {
log({
logDebug({
level: "debug",
message: `can't find path with config file, try to use default config`,
});
Expand Down Expand Up @@ -337,7 +338,7 @@ export function createCompileService({
*/
async function getMainFileForDocument(path: string) {
if (path.startsWith("untitled:")) {
log({ level: "debug", message: `untitled document treated as its own main file: ${path}` });
logDebug({ level: "debug", message: `untitled document treated as its own main file: ${path}` });
return path;
}

Expand Down
44 changes: 41 additions & 3 deletions packages/compiler/src/server/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CompilerOptions } from "../core/options.js";
import { getEnvironmentVariable } from "../utils/misc.js";

export const serverOptions: CompilerOptions = {
dryRun: true,
Expand All @@ -14,7 +15,44 @@ export const Commands = {
};

/**
* Environment variables to enable some logging when needed
* Debug areas that can be enabled via DEBUG environment variable.
* Usage: DEBUG=typespec:compile,typespec:config
*/
export const ENABLE_SERVER_COMPILE_LOGGING = "ENABLE_SERVER_COMPILE_LOGGING";
export const ENABLE_UPDATE_MANAGER_LOGGING = "ENABLE_UPDATE_MANAGER_LOGGING";
export const DebugAreas = {
SERVER_COMPILE: "typespec:compile",
UPDATE_MANAGER: "typespec:update",
COMPILE_CONFIG: "typespec:config",
} as const;

/**
* Check if a debug area is enabled via the DEBUG environment variable.
* Supports Node.js DEBUG pattern with wildcards and comma-separated values.
* Examples:
* DEBUG=typespec:compile
* DEBUG=typespec:*
* DEBUG=typespec:compile,typespec:config
*/
export function isDebugEnabled(area: string): boolean {
const debug = getEnvironmentVariable("DEBUG");
if (!debug) {
return false;
}

const areas = debug.split(",").map((a) => a.trim());

return areas.some((pattern) => {
// Exact match
if (pattern === area) {
return true;
}

// Wildcard pattern matching
if (pattern.includes("*")) {
const regexPattern = pattern.replace(/\*/g, ".*");
const regex = new RegExp(`^${regexPattern}$`);
return regex.test(area);
}

return false;
});
}
10 changes: 6 additions & 4 deletions packages/compiler/src/server/entrypoint-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { getDirectoryPath, joinPaths } from "../core/path-utils.js";
import { SystemHost, Diagnostic as TypeSpecDiagnostic } from "../core/types.js";
import { doIO, loadFile } from "../utils/io.js";
import { resolveTspMain } from "../utils/misc.js";
import { DebugAreas, isDebugEnabled } from "./constants.js";
import { FileSystemCache } from "./file-system-cache.js";
import { ServerLog } from "./types.js";

Expand All @@ -14,6 +15,7 @@ export async function resolveEntrypointFile(
log: (log: ServerLog) => void,
): Promise<string | undefined> {
const options = { allowFileNotFound: true };
const logDebug = isDebugEnabled(DebugAreas.COMPILE_CONFIG) ? log : () => {};

const pathStat = await doIO(() => host.stat(path), path, logMainFileSearchDiagnostic, options);
const isFilePath = pathStat?.isFile() ?? false;
Expand All @@ -36,22 +38,22 @@ export async function resolveEntrypointFile(

const tspMain = resolveTspMain(pkg);
if (typeof tspMain === "string") {
log({
logDebug({
level: "debug",
message: `tspMain resolved from package.json (${pkgPath}) as ${tspMain}`,
});

const packageJsonEntrypoint = await existingFile(dir, tspMain);
if (packageJsonEntrypoint) {
log({ level: "debug", message: `entrypoint file found as ${packageJsonEntrypoint}` });
logDebug({ level: "debug", message: `entrypoint file found as ${packageJsonEntrypoint}` });
return packageJsonEntrypoint;
}
}

for (const entrypoint of entrypoints) {
const candidate = await existingFile(dir, entrypoint);
if (candidate) {
log({
logDebug({
level: "debug",
message: `main file found using client provided entrypoint: ${candidate}`,
});
Expand All @@ -67,7 +69,7 @@ export async function resolveEntrypointFile(
dir = parentDir;
}

log({ level: "debug", message: `reached directory root, using '${path}' as main file` });
logDebug({ level: "debug", message: `reached directory root, using '${path}' as main file` });
return isFilePath ? path : undefined;

function logMainFileSearchDiagnostic(diagnostic: TypeSpecDiagnostic) {
Expand Down
9 changes: 4 additions & 5 deletions packages/compiler/src/server/server-compile-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
ServerLog,
} from "../index.js";
import { getEnvironmentVariable } from "../utils/misc.js";
import { ENABLE_SERVER_COMPILE_LOGGING } from "./constants.js";
import { DebugAreas, isDebugEnabled } from "./constants.js";
import { trackActionFunc } from "./server-track-action-task.js";
import { UpdateManager } from "./update-manager.js";

Expand Down Expand Up @@ -45,10 +45,9 @@ export class ServerCompileManager {
private compilerHost: CompilerHost,
private log: (log: ServerLog) => void,
) {
this.logDebug =
getEnvironmentVariable(ENABLE_SERVER_COMPILE_LOGGING)?.toLowerCase() === "true"
? (msg) => this.log({ level: "debug", message: msg })
: () => {};
this.logDebug = isDebugEnabled(DebugAreas.SERVER_COMPILE)
? (msg) => this.log({ level: "debug", message: msg })
: () => {};
}

async compile(
Expand Down
10 changes: 8 additions & 2 deletions packages/compiler/src/server/serverlib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ import { getSemanticTokens } from "./classify.js";
import { ClientConfigProvider } from "./client-config-provider.js";
import { createCompileService } from "./compile-service.js";
import { resolveCompletion } from "./completion.js";
import { Commands } from "./constants.js";
import { Commands, DebugAreas, isDebugEnabled } from "./constants.js";
import { convertDiagnosticToLsp } from "./diagnostics.js";
import { createFileService } from "./file-service.js";
import { createFileSystemCache } from "./file-system-cache.js";
Expand Down Expand Up @@ -1138,7 +1138,7 @@ export function createServer(
compilerHost,
emitterProvider,
linterProvider,
log,
log: logCompileConfig,
});
return CompletionList.create(items);
}
Expand Down Expand Up @@ -1412,6 +1412,12 @@ export function createServer(
host.log(log);
}

function logCompileConfig(logMessage: ServerLog) {
if (isDebugEnabled(DebugAreas.COMPILE_CONFIG)) {
log(logMessage);
}
}

function sendDiagnostics(document: TextDocument, diagnostics: VSDiagnostic[]) {
host.sendDiagnostics({
uri: document.uri,
Expand Down
13 changes: 6 additions & 7 deletions packages/compiler/src/server/update-manager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TextDocumentIdentifier } from "vscode-languageserver";
import { TextDocument } from "vscode-languageserver-textdocument";
import { getEnvironmentVariable } from "../utils/misc.js";
import { ENABLE_UPDATE_MANAGER_LOGGING } from "./constants.js";
import { DebugAreas, isDebugEnabled } from "./constants.js";
import { ServerLog } from "./types.js";

interface PendingUpdate {
Expand Down Expand Up @@ -43,12 +43,11 @@ export class UpdateManager<T = void> {
log: (sl: ServerLog) => void,
getDebounceDelay?: () => number,
) {
this._log =
getEnvironmentVariable(ENABLE_UPDATE_MANAGER_LOGGING)?.toLowerCase() === "true"
? (sl: ServerLog) => {
log({ ...sl, message: `#FromUpdateManager(${this.name}): ${sl.message}` });
}
: () => {};
this._log = isDebugEnabled(DebugAreas.UPDATE_MANAGER)
? (sl: ServerLog) => {
log({ ...sl, message: `#FromUpdateManager(${this.name}): ${sl.message}` });
}
: () => {};

// Set the debounce delay function once during construction
this.getDebounceDelay = getDebounceDelay ?? this.getAdaptiveDebounceDelay;
Expand Down