@formspec/ts-plugin 0.1.0-alpha.23 → 0.1.0-alpha.26

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 CHANGED
@@ -44,7 +44,6 @@ See:
44
44
  These source-repository references intentionally show a downstream host that
45
45
  renders diagnostics from `code` + `data` instead of reusing FormSpec's default
46
46
  message text.
47
-
48
47
  ## White-Label Diagnostics
49
48
 
50
49
  Diagnostics returned by the semantic service and plugin transport include:
package/dist/index.cjs CHANGED
@@ -516,6 +516,11 @@ var FormSpecPluginService = class {
516
516
  runtimePaths;
517
517
  semanticService;
518
518
  server = null;
519
+ /**
520
+ * Returns the manifest written by the plugin service for workspace discovery.
521
+ *
522
+ * @internal
523
+ */
519
524
  getManifest() {
520
525
  return this.manifest;
521
526
  }
@@ -527,6 +532,13 @@ var FormSpecPluginService = class {
527
532
  getSemanticService() {
528
533
  return this.semanticService;
529
534
  }
535
+ /**
536
+ * Starts the IPC transport and writes the current workspace manifest.
537
+ *
538
+ * Calling this more than once is a no-op.
539
+ *
540
+ * @public
541
+ */
530
542
  async start() {
531
543
  if (this.server !== null) {
532
544
  return;
@@ -584,6 +596,11 @@ var FormSpecPluginService = class {
584
596
  });
585
597
  await this.writeManifest();
586
598
  }
599
+ /**
600
+ * Stops the IPC transport, clears semantic state, and removes runtime artifacts.
601
+ *
602
+ * @public
603
+ */
587
604
  async stop() {
588
605
  this.semanticService.dispose();
589
606
  const server = this.server;
@@ -601,9 +618,19 @@ var FormSpecPluginService = class {
601
618
  }
602
619
  await this.cleanupRuntimeArtifacts();
603
620
  }
621
+ /**
622
+ * Schedules a background refresh for the cached semantic snapshot of a file.
623
+ *
624
+ * @public
625
+ */
604
626
  scheduleSnapshotRefresh(filePath) {
605
627
  this.semanticService.scheduleSnapshotRefresh(filePath);
606
628
  }
629
+ /**
630
+ * Handles a semantic query issued against the plugin transport.
631
+ *
632
+ * @internal
633
+ */
607
634
  handleQuery(query) {
608
635
  if (this.options.enablePerformanceLogging === true) {
609
636
  const startedAt = performance.now();
@@ -670,7 +697,7 @@ var FormSpecPluginService = class {
670
697
  respondToSocket(socket, payload) {
671
698
  try {
672
699
  const query = JSON.parse(payload);
673
- if (!(0, import_protocol3.isFormSpecSemanticQuery)(query)) {
700
+ if (!(0, import_internal3.isFormSpecSemanticQuery)(query)) {
674
701
  throw new Error("Invalid FormSpec semantic query payload");
675
702
  }
676
703
  const response = this.handleQuery(query);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/service.ts","../src/workspace.ts","../src/semantic-service.ts","../src/constants.ts","../src/perf-utils.ts"],"sourcesContent":["import type * as tsServer from \"typescript/lib/tsserverlibrary.js\";\nexport {\n FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n FORMSPEC_ANALYSIS_SCHEMA_VERSION,\n type CommentSourceSpan,\n type CommentSpan,\n type FormSpecAnalysisCommentSnapshot,\n type FormSpecAnalysisDiagnostic,\n type FormSpecAnalysisDiagnosticCategory,\n type FormSpecAnalysisDiagnosticDataValue,\n type FormSpecAnalysisDiagnosticLocation,\n type FormSpecAnalysisManifest,\n type FormSpecAnalysisFileSnapshot,\n type FormSpecAnalysisTagSnapshot,\n type FormSpecIpcEndpoint,\n type FormSpecPlacement,\n type FormSpecSemanticQuery,\n type FormSpecSemanticResponse,\n type FormSpecSerializedCommentTargetSpecifier,\n type FormSpecSerializedCompletionContext,\n type FormSpecSerializedHoverInfo,\n type FormSpecSerializedTagDefinition,\n type FormSpecSerializedTagSemanticContext,\n type FormSpecSerializedTagSignature,\n type FormSpecTargetKind,\n} from \"@formspec/analysis/protocol\";\nimport { createLanguageServiceProxy, FormSpecPluginService } from \"./service.js\";\nexport {\n createLanguageServiceProxy,\n FormSpecPluginService,\n type FormSpecPluginServiceOptions,\n type LoggerLike,\n} from \"./service.js\";\nexport {\n FormSpecSemanticService,\n type FormSpecSemanticCompletionResult,\n type FormSpecSemanticDiagnosticsResult,\n type FormSpecSemanticHoverResult,\n type FormSpecSemanticServiceOptions,\n type FormSpecSemanticServiceStats,\n} from \"./semantic-service.js\";\n\ninterface ServiceEntry {\n readonly service: FormSpecPluginService;\n referenceCount: number;\n}\n\nconst services = new Map<string, ServiceEntry>();\nconst PERF_LOG_ENV_VAR = \"FORMSPEC_PLUGIN_PROFILE\";\nconst PERF_LOG_THRESHOLD_ENV_VAR = \"FORMSPEC_PLUGIN_PROFILE_THRESHOLD_MS\";\n\nfunction formatPluginError(error: unknown): string {\n return error instanceof Error ? (error.stack ?? error.message) : String(error);\n}\n\nfunction readBooleanEnvFlag(name: string): boolean {\n const rawValue = process.env[name];\n return rawValue === \"1\" || rawValue === \"true\";\n}\n\nfunction readNumberEnvFlag(name: string): number | undefined {\n const rawValue = process.env[name];\n if (rawValue === undefined || rawValue.trim() === \"\") {\n return undefined;\n }\n\n const parsed = Number(rawValue);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction getOrCreateService(\n info: tsServer.server.PluginCreateInfo,\n typescriptVersion: string\n): FormSpecPluginService {\n const workspaceRoot = info.project.getCurrentDirectory();\n const existing = services.get(workspaceRoot);\n if (existing !== undefined) {\n existing.referenceCount += 1;\n attachProjectCloseHandler(info, workspaceRoot, existing);\n return existing.service;\n }\n\n const performanceLogThresholdMs = readNumberEnvFlag(PERF_LOG_THRESHOLD_ENV_VAR);\n const service = new FormSpecPluginService({\n workspaceRoot,\n typescriptVersion,\n getProgram: () => info.languageService.getProgram(),\n logger: info.project.projectService.logger,\n enablePerformanceLogging: readBooleanEnvFlag(PERF_LOG_ENV_VAR),\n ...(performanceLogThresholdMs === undefined ? {} : { performanceLogThresholdMs }),\n });\n\n const serviceEntry: ServiceEntry = {\n service,\n referenceCount: 1,\n };\n attachProjectCloseHandler(info, workspaceRoot, serviceEntry);\n\n service.start().catch((error: unknown) => {\n info.project.projectService.logger.info(\n `[FormSpec] Plugin service failed to start for ${workspaceRoot}: ${formatPluginError(error)}`\n );\n services.delete(workspaceRoot);\n });\n services.set(workspaceRoot, serviceEntry);\n return service;\n}\n\nfunction attachProjectCloseHandler(\n info: tsServer.server.PluginCreateInfo,\n workspaceRoot: string,\n serviceEntry: ServiceEntry\n): void {\n const originalClose = info.project.close.bind(info.project);\n let closed = false;\n\n info.project.close = () => {\n if (closed) {\n originalClose();\n return;\n }\n\n closed = true;\n serviceEntry.referenceCount -= 1;\n if (serviceEntry.referenceCount <= 0) {\n services.delete(workspaceRoot);\n void serviceEntry.service.stop().catch((error: unknown) => {\n info.project.projectService.logger.info(\n `[FormSpec] Failed to stop plugin service for ${workspaceRoot}: ${formatPluginError(error)}`\n );\n });\n }\n originalClose();\n };\n}\n\n/**\n * Initializes the FormSpec TypeScript language service plugin.\n *\n * @public\n */\nexport function init(modules: {\n readonly typescript: typeof tsServer;\n}): tsServer.server.PluginModule {\n const typescriptVersion = modules.typescript.version;\n return {\n create(info) {\n const service = getOrCreateService(info, typescriptVersion);\n return createLanguageServiceProxy(info.languageService, service.getSemanticService());\n },\n };\n}\n","import fs from \"node:fs/promises\";\nimport net from \"node:net\";\nimport * as ts from \"typescript\";\nimport {\n FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n isFormSpecSemanticQuery,\n type FormSpecAnalysisManifest,\n type FormSpecSemanticQuery,\n type FormSpecSemanticResponse,\n} from \"@formspec/analysis/protocol\";\nimport { type FormSpecPerformanceEvent } from \"@formspec/analysis/internal\";\nimport {\n createFormSpecAnalysisManifest,\n getFormSpecWorkspaceRuntimePaths,\n type FormSpecWorkspaceRuntimePaths,\n} from \"./workspace.js\";\nimport {\n FormSpecSemanticService,\n type FormSpecSemanticServiceOptions,\n type LoggerLike,\n} from \"./semantic-service.js\";\nimport {\n FORM_SPEC_PLUGIN_DEFAULT_PERFORMANCE_LOG_THRESHOLD_MS,\n FORM_SPEC_PLUGIN_MAX_SOCKET_PAYLOAD_BYTES,\n FORM_SPEC_PLUGIN_SOCKET_IDLE_TIMEOUT_MS,\n} from \"./constants.js\";\nimport { formatPerformanceEvent } from \"./perf-utils.js\";\n\n/**\n * Public configuration for the reference plugin wrapper that exposes\n * `FormSpecSemanticService` over the local manifest + IPC transport.\n *\n * Supports the same semantic-service options, including\n * `enablePerformanceLogging`, `performanceLogThresholdMs`, and\n * `snapshotDebounceMs`. The packaged tsserver plugin wires these from\n * `FORMSPEC_PLUGIN_PROFILE=1` and `FORMSPEC_PLUGIN_PROFILE_THRESHOLD_MS`.\n *\n * @public\n */\nexport type FormSpecPluginServiceOptions = FormSpecSemanticServiceOptions;\n\n/**\n * Reference manifest/socket wrapper around `FormSpecSemanticService`.\n *\n * Downstream TypeScript hosts that already control their own plugin/runtime\n * lifecycle can use `FormSpecSemanticService` directly and skip this wrapper.\n *\n * @public\n */\nexport class FormSpecPluginService {\n private readonly manifest: FormSpecAnalysisManifest;\n private readonly runtimePaths: FormSpecWorkspaceRuntimePaths;\n private readonly semanticService: FormSpecSemanticService;\n private server: net.Server | null = null;\n\n public constructor(private readonly options: FormSpecPluginServiceOptions) {\n this.semanticService = new FormSpecSemanticService(options);\n this.runtimePaths = getFormSpecWorkspaceRuntimePaths(options.workspaceRoot);\n this.manifest = createFormSpecAnalysisManifest(\n options.workspaceRoot,\n options.typescriptVersion,\n Date.now()\n );\n }\n\n public getManifest(): FormSpecAnalysisManifest {\n return this.manifest;\n }\n\n /**\n * Returns the underlying semantic service used by this reference wrapper.\n *\n * @public\n */\n public getSemanticService(): FormSpecSemanticService {\n return this.semanticService;\n }\n\n public async start(): Promise<void> {\n if (this.server !== null) {\n return;\n }\n\n await fs.mkdir(this.runtimePaths.runtimeDirectory, { recursive: true });\n if (this.runtimePaths.endpoint.kind === \"unix-socket\") {\n await fs.rm(this.runtimePaths.endpoint.address, { force: true });\n }\n\n this.server = net.createServer((socket) => {\n let buffer = \"\";\n socket.setEncoding(\"utf8\");\n socket.setTimeout(FORM_SPEC_PLUGIN_SOCKET_IDLE_TIMEOUT_MS, () => {\n this.options.logger?.info(\n `[FormSpec] Closing idle semantic query socket for ${this.runtimePaths.workspaceRoot}`\n );\n socket.destroy();\n });\n socket.on(\"data\", (chunk) => {\n buffer += String(chunk);\n if (buffer.length > FORM_SPEC_PLUGIN_MAX_SOCKET_PAYLOAD_BYTES) {\n socket.end(\n `${JSON.stringify({\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"error\",\n error: `FormSpec semantic query exceeded ${String(FORM_SPEC_PLUGIN_MAX_SOCKET_PAYLOAD_BYTES)} bytes`,\n } satisfies FormSpecSemanticResponse)}\\n`\n );\n return;\n }\n\n const newlineIndex = buffer.indexOf(\"\\n\");\n if (newlineIndex < 0) {\n return;\n }\n\n const payload = buffer.slice(0, newlineIndex);\n const remaining = buffer.slice(newlineIndex + 1);\n if (remaining.trim().length > 0) {\n this.options.logger?.info(\n `[FormSpec] Ignoring extra semantic query payload data for ${this.runtimePaths.workspaceRoot}`\n );\n }\n buffer = remaining;\n // The FormSpec IPC transport is intentionally one-request-per-connection.\n this.respondToSocket(socket, payload);\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n const handleError = (error: Error) => {\n reject(error);\n };\n this.server?.once(\"error\", handleError);\n this.server?.listen(this.runtimePaths.endpoint.address, () => {\n this.server?.off(\"error\", handleError);\n resolve();\n });\n });\n\n await this.writeManifest();\n }\n\n public async stop(): Promise<void> {\n this.semanticService.dispose();\n\n const server = this.server;\n this.server = null;\n if (server?.listening === true) {\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error === undefined) {\n resolve();\n return;\n }\n reject(error);\n });\n });\n }\n\n await this.cleanupRuntimeArtifacts();\n }\n\n public scheduleSnapshotRefresh(filePath: string): void {\n this.semanticService.scheduleSnapshotRefresh(filePath);\n }\n\n public handleQuery(query: FormSpecSemanticQuery): FormSpecSemanticResponse {\n if (this.options.enablePerformanceLogging === true) {\n const startedAt = performance.now();\n const response = this.executeQuery(query);\n this.logQueryDuration(query, performance.now() - startedAt);\n return response;\n }\n\n return this.executeQuery(query);\n }\n\n private executeQuery(query: FormSpecSemanticQuery): FormSpecSemanticResponse {\n switch (query.kind) {\n case \"health\":\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"health\",\n manifest: this.manifest,\n };\n case \"completion\": {\n const result = this.semanticService.getCompletionContext(query.filePath, query.offset);\n if (result === null) {\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"error\",\n error: `Unable to resolve TypeScript source file for ${query.filePath}`,\n };\n }\n\n return {\n ...result,\n kind: \"completion\",\n };\n }\n case \"hover\": {\n const result = this.semanticService.getHover(query.filePath, query.offset);\n if (result === null) {\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"error\",\n error: `Unable to resolve TypeScript source file for ${query.filePath}`,\n };\n }\n\n return {\n ...result,\n kind: \"hover\",\n };\n }\n case \"diagnostics\": {\n const result = this.semanticService.getDiagnostics(query.filePath);\n return {\n ...result,\n kind: \"diagnostics\",\n };\n }\n case \"file-snapshot\":\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"file-snapshot\",\n snapshot: this.semanticService.getFileSnapshot(query.filePath),\n };\n default: {\n throw new Error(`Unhandled semantic query: ${JSON.stringify(query)}`);\n }\n }\n }\n\n private respondToSocket(socket: net.Socket, payload: string): void {\n try {\n const query = JSON.parse(payload) as unknown;\n if (!isFormSpecSemanticQuery(query)) {\n throw new Error(\"Invalid FormSpec semantic query payload\");\n }\n const response = this.handleQuery(query);\n socket.end(`${JSON.stringify(response)}\\n`);\n } catch (error) {\n socket.end(\n `${JSON.stringify({\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"error\",\n error: error instanceof Error ? error.message : String(error),\n } satisfies FormSpecSemanticResponse)}\\n`\n );\n }\n }\n\n private async writeManifest(): Promise<void> {\n const tempManifestPath = `${this.runtimePaths.manifestPath}.tmp`;\n await fs.writeFile(tempManifestPath, `${JSON.stringify(this.manifest, null, 2)}\\n`, \"utf8\");\n await fs.rename(tempManifestPath, this.runtimePaths.manifestPath);\n }\n\n private async cleanupRuntimeArtifacts(): Promise<void> {\n await fs.rm(this.runtimePaths.manifestPath, { force: true });\n\n if (this.runtimePaths.endpoint.kind === \"unix-socket\") {\n await fs.rm(this.runtimePaths.endpoint.address, { force: true });\n }\n }\n\n private logQueryDuration(query: FormSpecSemanticQuery, durationMs: number): void {\n const logger = this.options.logger;\n if (logger === undefined) {\n return;\n }\n\n const thresholdMs =\n this.options.performanceLogThresholdMs ??\n FORM_SPEC_PLUGIN_DEFAULT_PERFORMANCE_LOG_THRESHOLD_MS;\n if (durationMs < thresholdMs) {\n return;\n }\n\n const event: FormSpecPerformanceEvent = {\n name: \"plugin.handleQuery\",\n durationMs,\n detail: {\n kind: query.kind,\n ...(query.kind === \"health\" ? {} : { filePath: query.filePath }),\n },\n };\n logger.info(`[FormSpec][perf] ${formatPerformanceEvent(event)}`);\n }\n}\n\n/**\n * Reference proxy wrapper that keeps FormSpec semantic snapshots fresh while\n * delegating actual TypeScript editor features to the original service.\n *\n * @public\n */\nexport function createLanguageServiceProxy(\n languageService: ts.LanguageService,\n semanticService: FormSpecSemanticService\n): ts.LanguageService {\n const wrapWithSnapshotRefresh = <Args extends readonly unknown[], Result>(\n fn: (fileName: string, ...args: Args) => Result\n ) => {\n return (fileName: string, ...args: Args): Result => {\n semanticService.scheduleSnapshotRefresh(fileName);\n return fn(fileName, ...args);\n };\n };\n\n const getSemanticDiagnostics = wrapWithSnapshotRefresh((fileName) =>\n languageService.getSemanticDiagnostics(fileName)\n );\n\n const getCompletionsAtPosition = wrapWithSnapshotRefresh(\n (fileName: string, position: number, options: ts.GetCompletionsAtPositionOptions | undefined) =>\n languageService.getCompletionsAtPosition(fileName, position, options)\n );\n\n const getQuickInfoAtPosition = wrapWithSnapshotRefresh((fileName, position: number) =>\n languageService.getQuickInfoAtPosition(fileName, position)\n );\n\n return new Proxy(languageService, {\n get(target, property, receiver) {\n switch (property) {\n case \"getSemanticDiagnostics\":\n return getSemanticDiagnostics;\n case \"getCompletionsAtPosition\":\n return getCompletionsAtPosition;\n case \"getQuickInfoAtPosition\":\n return getQuickInfoAtPosition;\n default:\n return Reflect.get(target, property, receiver) as unknown;\n }\n },\n });\n}\n\nexport type { LoggerLike };\n","import os from \"node:os\";\nimport path from \"node:path\";\nimport {\n FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n FORMSPEC_ANALYSIS_SCHEMA_VERSION,\n type FormSpecAnalysisManifest,\n type FormSpecIpcEndpoint,\n} from \"@formspec/analysis/protocol\";\nimport {\n getFormSpecManifestPath,\n getFormSpecWorkspaceId,\n getFormSpecWorkspaceRuntimeDirectory,\n} from \"@formspec/analysis/internal\";\n\nexport interface FormSpecWorkspaceRuntimePaths {\n readonly workspaceRoot: string;\n readonly workspaceId: string;\n readonly runtimeDirectory: string;\n readonly manifestPath: string;\n readonly endpoint: FormSpecIpcEndpoint;\n}\n\nexport function getFormSpecWorkspaceRuntimePaths(\n workspaceRoot: string,\n platform = process.platform,\n userScope = getFormSpecUserScope()\n): FormSpecWorkspaceRuntimePaths {\n const workspaceId = getFormSpecWorkspaceId(workspaceRoot);\n const runtimeDirectory = getFormSpecWorkspaceRuntimeDirectory(workspaceRoot);\n const sanitizedUserScope = sanitizeScopeSegment(userScope);\n const endpoint: FormSpecIpcEndpoint =\n platform === \"win32\"\n ? {\n kind: \"windows-pipe\",\n address: `\\\\\\\\.\\\\pipe\\\\formspec-${sanitizedUserScope}-${workspaceId}`,\n }\n : {\n kind: \"unix-socket\",\n address: path.join(os.tmpdir(), `formspec-${sanitizedUserScope}-${workspaceId}.sock`),\n };\n\n return {\n workspaceRoot,\n workspaceId,\n runtimeDirectory,\n manifestPath: getFormSpecManifestPath(workspaceRoot),\n endpoint,\n };\n}\n\nexport function createFormSpecAnalysisManifest(\n workspaceRoot: string,\n typescriptVersion: string,\n generation: number,\n extensionFingerprint = \"builtin\"\n): FormSpecAnalysisManifest {\n const paths = getFormSpecWorkspaceRuntimePaths(workspaceRoot);\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n analysisSchemaVersion: FORMSPEC_ANALYSIS_SCHEMA_VERSION,\n workspaceRoot,\n workspaceId: paths.workspaceId,\n endpoint: paths.endpoint,\n typescriptVersion,\n extensionFingerprint,\n generation,\n updatedAt: new Date().toISOString(),\n };\n}\n\nfunction getFormSpecUserScope(): string {\n try {\n return sanitizeScopeSegment(os.userInfo().username);\n } catch {\n return sanitizeScopeSegment(\n process.env[\"USER\"] ?? process.env[\"USERNAME\"] ?? process.env[\"LOGNAME\"] ?? \"formspec\"\n );\n }\n}\n\nfunction sanitizeScopeSegment(value: string): string {\n const trimmed = value.trim().toLowerCase();\n const sanitized = trimmed.replace(/[^a-z0-9_-]+/gu, \"-\").replace(/-+/gu, \"-\");\n return sanitized.length > 0 ? sanitized : \"formspec\";\n}\n","import * as ts from \"typescript\";\nimport {\n FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n computeFormSpecTextHash,\n type FormSpecAnalysisDiagnostic,\n type FormSpecAnalysisFileSnapshot,\n type FormSpecSerializedCompletionContext,\n type FormSpecSerializedHoverInfo,\n} from \"@formspec/analysis/protocol\";\nimport {\n buildFormSpecAnalysisFileSnapshot,\n createFormSpecPerformanceRecorder,\n findDeclarationForCommentOffset,\n getCommentHoverInfoAtOffset,\n getSemanticCommentCompletionContextAtOffset,\n getFormSpecPerformanceNow,\n getSubjectType,\n optionalMeasure,\n resolveDeclarationPlacement,\n serializeCompletionContext,\n serializeHoverInfo,\n type BuildFormSpecAnalysisFileSnapshotOptions,\n type FormSpecPerformanceEvent,\n type FormSpecPerformanceRecorder,\n} from \"@formspec/analysis/internal\";\nimport {\n FORM_SPEC_PLUGIN_DEFAULT_PERFORMANCE_LOG_THRESHOLD_MS,\n FORM_SPEC_PLUGIN_DEFAULT_SNAPSHOT_DEBOUNCE_MS,\n} from \"./constants.js\";\nimport { formatPerformanceEvent } from \"./perf-utils.js\";\n\n/** @public */\nexport interface LoggerLike {\n info(message: string): void;\n}\n\n/** @public */\nexport interface FormSpecSemanticServiceOptions {\n /** Workspace root used for runtime paths and contextual logging. */\n readonly workspaceRoot: string;\n /** TypeScript version string reported by the host runtime. */\n readonly typescriptVersion: string;\n /** Supplies the current host program. Returns `undefined` until ready. */\n readonly getProgram: () => ts.Program | undefined;\n /** Optional logger used for profiling and refresh-failure messages. */\n readonly logger?: LoggerLike;\n /** Enables structured hotspot logging for semantic queries. */\n readonly enablePerformanceLogging?: boolean;\n /** Minimum query duration, in milliseconds, required before logging. */\n readonly performanceLogThresholdMs?: number;\n /** Debounce window, in milliseconds, for background snapshot refresh. */\n readonly snapshotDebounceMs?: number;\n /** Injectable clock used by tests and runtime snapshot timestamps. */\n readonly now?: () => Date;\n}\n\n/** @public */\nexport interface FormSpecSemanticCompletionResult {\n readonly protocolVersion: typeof FORMSPEC_ANALYSIS_PROTOCOL_VERSION;\n readonly sourceHash: string;\n readonly context: FormSpecSerializedCompletionContext;\n}\n\n/** @public */\nexport interface FormSpecSemanticHoverResult {\n readonly protocolVersion: typeof FORMSPEC_ANALYSIS_PROTOCOL_VERSION;\n readonly sourceHash: string;\n readonly hover: FormSpecSerializedHoverInfo | null;\n}\n\n/** @public */\nexport interface FormSpecSemanticDiagnosticsResult {\n readonly protocolVersion: typeof FORMSPEC_ANALYSIS_PROTOCOL_VERSION;\n readonly sourceHash: string;\n readonly diagnostics: readonly FormSpecAnalysisDiagnostic[];\n}\n\n/** @public */\nexport interface FormSpecSemanticServiceStats {\n /** Total number of calls by semantic query kind. */\n readonly queryTotals: {\n readonly completion: number;\n readonly hover: number;\n readonly diagnostics: number;\n readonly fileSnapshot: number;\n };\n /** Cold vs warm query path counts for snapshot-backed operations. */\n readonly queryPathTotals: {\n readonly diagnostics: { readonly cold: number; readonly warm: number };\n readonly fileSnapshot: { readonly cold: number; readonly warm: number };\n };\n /** Number of file snapshot cache hits. */\n readonly fileSnapshotCacheHits: number;\n /** Number of file snapshot cache misses. */\n readonly fileSnapshotCacheMisses: number;\n /** Number of synthetic batch cache hits. */\n readonly syntheticBatchCacheHits: number;\n /** Number of synthetic batch cache misses. */\n readonly syntheticBatchCacheMisses: number;\n /** Number of synthetic compiler program creations. */\n readonly syntheticCompileCount: number;\n /** Total synthetic application count compiled across misses. */\n readonly syntheticCompileApplications: number;\n}\n\ninterface CachedFileSnapshot {\n readonly sourceHash: string;\n readonly snapshot: FormSpecAnalysisFileSnapshot;\n}\n\ninterface SourceEnvironment {\n readonly sourceFile: ts.SourceFile;\n readonly checker: ts.TypeChecker;\n readonly sourceHash: string;\n}\n\ninterface CommentQueryContext extends SourceEnvironment {\n readonly declaration: ts.Node | null;\n readonly placement: ReturnType<typeof resolveDeclarationPlacement>;\n readonly subjectType: ts.Type | undefined;\n}\n\ntype SnapshotCacheState = \"hit\" | \"miss\" | \"missing-source\";\n\ninterface MutableSemanticServiceStats {\n queryTotals: {\n completion: number;\n hover: number;\n diagnostics: number;\n fileSnapshot: number;\n };\n queryPathTotals: {\n diagnostics: { cold: number; warm: number };\n fileSnapshot: { cold: number; warm: number };\n };\n fileSnapshotCacheHits: number;\n fileSnapshotCacheMisses: number;\n syntheticBatchCacheHits: number;\n syntheticBatchCacheMisses: number;\n syntheticCompileCount: number;\n syntheticCompileApplications: number;\n}\n\nconst STATS_ONLY_EVENT_NAMES = new Set<string>([\n \"analysis.syntheticCheckBatch.cacheHit\",\n \"analysis.narrowSyntheticCheckBatch.cacheHit\",\n \"analysis.syntheticCheckBatch.cacheMiss\",\n \"analysis.narrowSyntheticCheckBatch.cacheMiss\",\n \"analysis.syntheticCheckBatch.createProgram\",\n \"analysis.narrowSyntheticCheckBatch.createProgram\",\n]);\n\nclass StatsOnlyPerformanceRecorder implements FormSpecPerformanceRecorder {\n private readonly mutableEvents: FormSpecPerformanceEvent[] = [];\n\n public get events(): readonly FormSpecPerformanceEvent[] {\n return this.mutableEvents;\n }\n\n public measure<T>(\n name: string,\n detail: Readonly<Record<string, string | number | boolean>> | undefined,\n callback: () => T\n ): T {\n const result = callback();\n if (STATS_ONLY_EVENT_NAMES.has(name)) {\n this.mutableEvents.push({\n name,\n durationMs: 0,\n ...(detail === undefined ? {} : { detail }),\n });\n }\n return result;\n }\n\n public record(event: FormSpecPerformanceEvent): void {\n if (STATS_ONLY_EVENT_NAMES.has(event.name)) {\n this.mutableEvents.push(event);\n }\n }\n}\n\n/**\n * Reusable in-process semantic service for FormSpec authoring features.\n *\n * Downstream TypeScript hosts can construct this directly against their own\n * `Program` and own the final presentation of completions, hover, and\n * diagnostics. The shipped tsserver plugin is a reference wrapper over this\n * public service.\n *\n * @public\n */\nexport class FormSpecSemanticService {\n private readonly snapshotCache = new Map<string, CachedFileSnapshot>();\n private readonly refreshTimers = new Map<string, NodeJS.Timeout>();\n private readonly stats: MutableSemanticServiceStats = {\n queryTotals: {\n completion: 0,\n hover: 0,\n diagnostics: 0,\n fileSnapshot: 0,\n },\n queryPathTotals: {\n diagnostics: { cold: 0, warm: 0 },\n fileSnapshot: { cold: 0, warm: 0 },\n },\n fileSnapshotCacheHits: 0,\n fileSnapshotCacheMisses: 0,\n syntheticBatchCacheHits: 0,\n syntheticBatchCacheMisses: 0,\n syntheticCompileCount: 0,\n syntheticCompileApplications: 0,\n };\n\n public constructor(private readonly options: FormSpecSemanticServiceOptions) {}\n\n /** Resolves semantic completion context for a comment cursor position. */\n public getCompletionContext(\n filePath: string,\n offset: number\n ): FormSpecSemanticCompletionResult | null {\n this.stats.queryTotals.completion += 1;\n return this.runMeasured(\"semantic.getCompletionContext\", { filePath, offset }, (performance) =>\n this.withCommentQueryContext(filePath, offset, performance, (context) => ({\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n sourceHash: context.sourceHash,\n context: serializeCompletionContext(\n getSemanticCommentCompletionContextAtOffset(context.sourceFile.text, offset, {\n checker: context.checker,\n ...(context.placement === null ? {} : { placement: context.placement }),\n ...(context.subjectType === undefined ? {} : { subjectType: context.subjectType }),\n })\n ),\n }))\n );\n }\n\n /** Resolves semantic hover payload for a comment cursor position. */\n public getHover(filePath: string, offset: number): FormSpecSemanticHoverResult | null {\n this.stats.queryTotals.hover += 1;\n return this.runMeasured(\"semantic.getHover\", { filePath, offset }, (performance) =>\n this.withCommentQueryContext(filePath, offset, performance, (context) => ({\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n sourceHash: context.sourceHash,\n hover: serializeHoverInfo(\n getCommentHoverInfoAtOffset(context.sourceFile.text, offset, {\n checker: context.checker,\n ...(context.placement === null ? {} : { placement: context.placement }),\n ...(context.subjectType === undefined ? {} : { subjectType: context.subjectType }),\n })\n ),\n }))\n );\n }\n\n /** Returns canonical FormSpec diagnostics for a file in the current host program. */\n public getDiagnostics(filePath: string): FormSpecSemanticDiagnosticsResult {\n this.stats.queryTotals.diagnostics += 1;\n return this.runMeasured(\"semantic.getDiagnostics\", { filePath }, (performance) => {\n const { snapshot, cacheState } = this.getFileSnapshotWithCacheState(filePath, performance);\n this.recordQueryPath(\"diagnostics\", cacheState);\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n sourceHash: snapshot.sourceHash,\n diagnostics: snapshot.diagnostics,\n };\n });\n }\n\n /** Returns the full serialized semantic snapshot for a file. */\n public getFileSnapshot(filePath: string): FormSpecAnalysisFileSnapshot {\n this.stats.queryTotals.fileSnapshot += 1;\n return this.runMeasured(\"semantic.getFileSnapshot\", { filePath }, (performance) => {\n const { snapshot, cacheState } = this.getFileSnapshotWithCacheState(filePath, performance);\n this.recordQueryPath(\"fileSnapshot\", cacheState);\n return snapshot;\n });\n }\n\n /** Schedules a debounced background refresh for the file snapshot cache. */\n public scheduleSnapshotRefresh(filePath: string): void {\n const existing = this.refreshTimers.get(filePath);\n if (existing !== undefined) {\n clearTimeout(existing);\n }\n\n const timer = setTimeout(() => {\n try {\n this.getFileSnapshot(filePath);\n } catch (error: unknown) {\n this.options.logger?.info(\n `[FormSpec] Failed to refresh semantic snapshot for ${filePath}: ${String(error)}`\n );\n }\n this.refreshTimers.delete(filePath);\n }, this.options.snapshotDebounceMs ?? FORM_SPEC_PLUGIN_DEFAULT_SNAPSHOT_DEBOUNCE_MS);\n timer.unref();\n\n this.refreshTimers.set(filePath, timer);\n }\n\n /** Clears pending timers and cached semantic snapshots. */\n public dispose(): void {\n for (const timer of this.refreshTimers.values()) {\n clearTimeout(timer);\n }\n this.refreshTimers.clear();\n this.snapshotCache.clear();\n }\n\n /** Returns a copy of the current performance and cache counters. */\n public getStats(): FormSpecSemanticServiceStats {\n return {\n queryTotals: { ...this.stats.queryTotals },\n queryPathTotals: {\n diagnostics: { ...this.stats.queryPathTotals.diagnostics },\n fileSnapshot: { ...this.stats.queryPathTotals.fileSnapshot },\n },\n fileSnapshotCacheHits: this.stats.fileSnapshotCacheHits,\n fileSnapshotCacheMisses: this.stats.fileSnapshotCacheMisses,\n syntheticBatchCacheHits: this.stats.syntheticBatchCacheHits,\n syntheticBatchCacheMisses: this.stats.syntheticBatchCacheMisses,\n syntheticCompileCount: this.stats.syntheticCompileCount,\n syntheticCompileApplications: this.stats.syntheticCompileApplications,\n };\n }\n\n private runMeasured<T>(\n name: string,\n detail: Record<string, string | number>,\n fn: (performance: FormSpecPerformanceRecorder) => T\n ): T {\n const performance =\n this.options.enablePerformanceLogging === true\n ? createFormSpecPerformanceRecorder()\n : new StatsOnlyPerformanceRecorder();\n const result = optionalMeasure(performance, name, detail, () => fn(performance));\n this.updateStatsFromPerformanceEvents(performance.events);\n if (this.options.enablePerformanceLogging === true) {\n this.logPerformanceEvents(name, performance.events);\n }\n return result;\n }\n\n private withCommentQueryContext<T>(\n filePath: string,\n offset: number,\n performance: FormSpecPerformanceRecorder,\n handler: (context: CommentQueryContext) => T\n ): T | null {\n return optionalMeasure(\n performance,\n \"semantic.resolveCommentQueryContext\",\n {\n filePath,\n offset,\n },\n () => {\n const environment = this.getSourceEnvironment(filePath, performance);\n if (environment === null) {\n return null;\n }\n\n const declaration = optionalMeasure(\n performance,\n \"semantic.findDeclarationForCommentOffset\",\n {\n filePath,\n offset,\n },\n () => findDeclarationForCommentOffset(environment.sourceFile, offset)\n );\n const placement =\n declaration === null\n ? null\n : optionalMeasure(performance, \"semantic.resolveDeclarationPlacement\", undefined, () =>\n resolveDeclarationPlacement(declaration)\n );\n const subjectType =\n declaration === null\n ? undefined\n : optionalMeasure(performance, \"semantic.getSubjectType\", undefined, () =>\n getSubjectType(declaration, environment.checker)\n );\n\n return handler({\n ...environment,\n declaration,\n placement,\n subjectType,\n });\n }\n );\n }\n\n private getFileSnapshotWithCacheState(\n filePath: string,\n performance: FormSpecPerformanceRecorder\n ): {\n readonly snapshot: FormSpecAnalysisFileSnapshot;\n readonly cacheState: SnapshotCacheState;\n } {\n const startedAt = getFormSpecPerformanceNow();\n const environment = this.getSourceEnvironment(filePath, performance);\n if (environment === null) {\n this.stats.fileSnapshotCacheMisses += 1;\n const snapshot: FormSpecAnalysisFileSnapshot = {\n filePath,\n sourceHash: \"\",\n generatedAt: this.getNow().toISOString(),\n comments: [],\n diagnostics: [\n {\n code: \"MISSING_SOURCE_FILE\",\n category: \"infrastructure\",\n message: `Unable to resolve TypeScript source file for ${filePath}`,\n range: { start: 0, end: 0 },\n severity: \"warning\",\n relatedLocations: [],\n data: {\n filePath,\n },\n },\n ],\n };\n performance.record({\n name: \"semantic.getFileSnapshot.result\",\n durationMs: getFormSpecPerformanceNow() - startedAt,\n detail: {\n filePath,\n cache: \"missing-source\",\n },\n });\n return {\n snapshot,\n cacheState: \"missing-source\",\n };\n }\n\n const cached = this.snapshotCache.get(filePath);\n if (cached?.sourceHash === environment.sourceHash) {\n this.stats.fileSnapshotCacheHits += 1;\n performance.record({\n name: \"semantic.getFileSnapshot.result\",\n durationMs: getFormSpecPerformanceNow() - startedAt,\n detail: {\n filePath,\n cache: \"hit\",\n },\n });\n return {\n snapshot: cached.snapshot,\n cacheState: \"hit\",\n };\n }\n\n this.stats.fileSnapshotCacheMisses += 1;\n const snapshot = buildFormSpecAnalysisFileSnapshot(environment.sourceFile, {\n checker: environment.checker,\n now: () => this.getNow(),\n performance,\n } satisfies BuildFormSpecAnalysisFileSnapshotOptions);\n this.snapshotCache.set(filePath, {\n sourceHash: environment.sourceHash,\n snapshot,\n });\n performance.record({\n name: \"semantic.getFileSnapshot.result\",\n durationMs: getFormSpecPerformanceNow() - startedAt,\n detail: {\n filePath,\n cache: \"miss\",\n },\n });\n return {\n snapshot,\n cacheState: \"miss\",\n };\n }\n\n private getNow(): Date {\n return this.options.now?.() ?? new Date();\n }\n\n private getSourceEnvironment(\n filePath: string,\n performance: FormSpecPerformanceRecorder\n ): SourceEnvironment | null {\n return optionalMeasure(\n performance,\n \"semantic.getSourceEnvironment\",\n {\n filePath,\n },\n () => {\n const program = optionalMeasure(\n performance,\n \"semantic.sourceEnvironment.getProgram\",\n undefined,\n () => this.options.getProgram()\n );\n if (program === undefined) {\n return null;\n }\n\n const sourceFile = optionalMeasure(\n performance,\n \"semantic.sourceEnvironment.getSourceFile\",\n undefined,\n () => program.getSourceFile(filePath)\n );\n if (sourceFile === undefined) {\n return null;\n }\n\n const checker = optionalMeasure(\n performance,\n \"semantic.sourceEnvironment.getTypeChecker\",\n undefined,\n () => program.getTypeChecker()\n );\n const sourceHash = optionalMeasure(\n performance,\n \"semantic.sourceEnvironment.computeTextHash\",\n undefined,\n () => computeFormSpecTextHash(sourceFile.text)\n );\n\n return {\n sourceFile,\n checker,\n sourceHash,\n };\n }\n );\n }\n\n private recordQueryPath(\n kind: \"diagnostics\" | \"fileSnapshot\",\n cacheState: SnapshotCacheState\n ): void {\n if (cacheState === \"hit\") {\n this.stats.queryPathTotals[kind].warm += 1;\n return;\n }\n\n this.stats.queryPathTotals[kind].cold += 1;\n }\n\n private updateStatsFromPerformanceEvents(events: readonly FormSpecPerformanceEvent[]): void {\n for (const event of events) {\n if (\n event.name === \"analysis.syntheticCheckBatch.cacheHit\" ||\n event.name === \"analysis.narrowSyntheticCheckBatch.cacheHit\"\n ) {\n this.stats.syntheticBatchCacheHits += 1;\n continue;\n }\n\n if (\n event.name === \"analysis.syntheticCheckBatch.cacheMiss\" ||\n event.name === \"analysis.narrowSyntheticCheckBatch.cacheMiss\"\n ) {\n this.stats.syntheticBatchCacheMisses += 1;\n const applicationCount = event.detail?.[\"applicationCount\"];\n if (typeof applicationCount === \"number\") {\n this.stats.syntheticCompileApplications += applicationCount;\n }\n continue;\n }\n\n if (\n event.name === \"analysis.syntheticCheckBatch.createProgram\" ||\n event.name === \"analysis.narrowSyntheticCheckBatch.createProgram\"\n ) {\n this.stats.syntheticCompileCount += 1;\n }\n }\n }\n\n private logPerformanceEvents(\n rootEventName: string,\n events: readonly FormSpecPerformanceEvent[]\n ): void {\n const logger = this.options.logger;\n if (logger === undefined || events.length === 0) {\n return;\n }\n\n const rootEvent = [...events].reverse().find((event) => event.name === rootEventName);\n if (rootEvent === undefined) {\n return;\n }\n\n const thresholdMs =\n this.options.performanceLogThresholdMs ??\n FORM_SPEC_PLUGIN_DEFAULT_PERFORMANCE_LOG_THRESHOLD_MS;\n if (rootEvent.durationMs < thresholdMs) {\n return;\n }\n\n const sortedHotspots = [...events]\n .filter((event) => event.name !== rootEventName)\n .sort((left, right) => right.durationMs - left.durationMs)\n .slice(0, 8);\n const lines = [\n `[FormSpec][perf] ${formatPerformanceEvent(rootEvent)}`,\n ...sortedHotspots.map((event) => ` ${formatPerformanceEvent(event)}`),\n ];\n logger.info(lines.join(\"\\n\"));\n }\n}\n","export const FORM_SPEC_PLUGIN_MAX_SOCKET_PAYLOAD_BYTES = 256 * 1024;\nexport const FORM_SPEC_PLUGIN_SOCKET_IDLE_TIMEOUT_MS = 30_000;\nexport const FORM_SPEC_PLUGIN_DEFAULT_PERFORMANCE_LOG_THRESHOLD_MS = 50;\nexport const FORM_SPEC_PLUGIN_DEFAULT_SNAPSHOT_DEBOUNCE_MS = 250;\n\nexport const FORM_SPEC_PLUGIN_PERFORMANCE_EVENT = {\n handleQuery: \"plugin.handleQuery\",\n} as const;\n","import type { FormSpecPerformanceEvent } from \"@formspec/analysis/internal\";\n\nexport function formatPerformanceEvent(event: FormSpecPerformanceEvent): string {\n const detailEntries = Object.entries(event.detail ?? {})\n .map(([key, value]) => `${key}=${String(value)}`)\n .join(\" \");\n return `${event.durationMs.toFixed(1)}ms ${event.name}${detailEntries === \"\" ? \"\" : ` ${detailEntries}`}`;\n}\n"],"mappings":"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","names":["import_protocol","ts","import_protocol","import_internal","path","os","import_protocol","import_internal","performance","snapshot","fs","net"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/service.ts","../src/workspace.ts","../src/semantic-service.ts","../src/constants.ts","../src/perf-utils.ts"],"sourcesContent":["/**\n * TypeScript language service plugin entrypoint for FormSpec.\n *\n * This package exposes the reference tsserver plugin and the reusable semantic\n * service used by downstream TypeScript hosts.\n *\n * @packageDocumentation\n */\nimport type * as tsServer from \"typescript/lib/tsserverlibrary.js\";\nexport {\n FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n FORMSPEC_ANALYSIS_SCHEMA_VERSION,\n type CommentHoverInfo,\n type CommentSourceSpan,\n type CommentSpan,\n type FormSpecAnalysisCommentSnapshot,\n type FormSpecAnalysisDiagnostic,\n type FormSpecAnalysisDiagnosticCategory,\n type FormSpecAnalysisDiagnosticDataValue,\n type FormSpecAnalysisDiagnosticLocation,\n type FormSpecAnalysisFileSnapshot,\n type FormSpecAnalysisTagSnapshot,\n type FormSpecPlacement,\n type FormSpecTargetKind,\n type FormSpecSerializedCommentTargetSpecifier,\n type FormSpecSerializedCompletionContext,\n type FormSpecSerializedHoverInfo,\n type FormSpecSerializedTagDefinition,\n type FormSpecSerializedTagSemanticContext,\n type FormSpecSerializedTagSignature,\n} from \"@formspec/analysis/protocol\";\nimport { createLanguageServiceProxy, FormSpecPluginService } from \"./service.js\";\nexport {\n createLanguageServiceProxy,\n FormSpecPluginService,\n type FormSpecPluginServiceOptions,\n type LoggerLike,\n} from \"./service.js\";\nexport {\n FormSpecSemanticService,\n type FormSpecSemanticCompletionResult,\n type FormSpecSemanticDiagnosticsResult,\n type FormSpecSemanticHoverResult,\n type FormSpecSemanticServiceOptions,\n type FormSpecSemanticServiceStats,\n} from \"./semantic-service.js\";\n\ninterface ServiceEntry {\n readonly service: FormSpecPluginService;\n referenceCount: number;\n}\n\nconst services = new Map<string, ServiceEntry>();\nconst PERF_LOG_ENV_VAR = \"FORMSPEC_PLUGIN_PROFILE\";\nconst PERF_LOG_THRESHOLD_ENV_VAR = \"FORMSPEC_PLUGIN_PROFILE_THRESHOLD_MS\";\n\nfunction formatPluginError(error: unknown): string {\n return error instanceof Error ? (error.stack ?? error.message) : String(error);\n}\n\nfunction readBooleanEnvFlag(name: string): boolean {\n const rawValue = process.env[name];\n return rawValue === \"1\" || rawValue === \"true\";\n}\n\nfunction readNumberEnvFlag(name: string): number | undefined {\n const rawValue = process.env[name];\n if (rawValue === undefined || rawValue.trim() === \"\") {\n return undefined;\n }\n\n const parsed = Number(rawValue);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction getOrCreateService(\n info: tsServer.server.PluginCreateInfo,\n typescriptVersion: string\n): FormSpecPluginService {\n const workspaceRoot = info.project.getCurrentDirectory();\n const existing = services.get(workspaceRoot);\n if (existing !== undefined) {\n existing.referenceCount += 1;\n attachProjectCloseHandler(info, workspaceRoot, existing);\n return existing.service;\n }\n\n const performanceLogThresholdMs = readNumberEnvFlag(PERF_LOG_THRESHOLD_ENV_VAR);\n const service = new FormSpecPluginService({\n workspaceRoot,\n typescriptVersion,\n getProgram: () => info.languageService.getProgram(),\n logger: info.project.projectService.logger,\n enablePerformanceLogging: readBooleanEnvFlag(PERF_LOG_ENV_VAR),\n ...(performanceLogThresholdMs === undefined ? {} : { performanceLogThresholdMs }),\n });\n\n const serviceEntry: ServiceEntry = {\n service,\n referenceCount: 1,\n };\n attachProjectCloseHandler(info, workspaceRoot, serviceEntry);\n\n service.start().catch((error: unknown) => {\n info.project.projectService.logger.info(\n `[FormSpec] Plugin service failed to start for ${workspaceRoot}: ${formatPluginError(error)}`\n );\n services.delete(workspaceRoot);\n });\n services.set(workspaceRoot, serviceEntry);\n return service;\n}\n\nfunction attachProjectCloseHandler(\n info: tsServer.server.PluginCreateInfo,\n workspaceRoot: string,\n serviceEntry: ServiceEntry\n): void {\n const originalClose = info.project.close.bind(info.project);\n let closed = false;\n\n info.project.close = () => {\n if (closed) {\n originalClose();\n return;\n }\n\n closed = true;\n serviceEntry.referenceCount -= 1;\n if (serviceEntry.referenceCount <= 0) {\n services.delete(workspaceRoot);\n void serviceEntry.service.stop().catch((error: unknown) => {\n info.project.projectService.logger.info(\n `[FormSpec] Failed to stop plugin service for ${workspaceRoot}: ${formatPluginError(error)}`\n );\n });\n }\n originalClose();\n };\n}\n\n/**\n * Initializes the FormSpec TypeScript language service plugin.\n *\n * @public\n */\nexport function init(modules: {\n readonly typescript: typeof tsServer;\n}): tsServer.server.PluginModule {\n const typescriptVersion = modules.typescript.version;\n return {\n create(info) {\n const service = getOrCreateService(info, typescriptVersion);\n return createLanguageServiceProxy(info.languageService, service.getSemanticService());\n },\n };\n}\n","import fs from \"node:fs/promises\";\nimport net from \"node:net\";\nimport * as ts from \"typescript\";\nimport {\n FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n} from \"@formspec/analysis/protocol\";\nimport {\n isFormSpecSemanticQuery,\n type FormSpecAnalysisManifest,\n type FormSpecPerformanceEvent,\n type FormSpecSemanticQuery,\n type FormSpecSemanticResponse,\n} from \"@formspec/analysis/internal\";\nimport {\n createFormSpecAnalysisManifest,\n getFormSpecWorkspaceRuntimePaths,\n type FormSpecWorkspaceRuntimePaths,\n} from \"./workspace.js\";\nimport {\n FormSpecSemanticService,\n type FormSpecSemanticServiceOptions,\n type LoggerLike,\n} from \"./semantic-service.js\";\nimport {\n FORM_SPEC_PLUGIN_DEFAULT_PERFORMANCE_LOG_THRESHOLD_MS,\n FORM_SPEC_PLUGIN_MAX_SOCKET_PAYLOAD_BYTES,\n FORM_SPEC_PLUGIN_SOCKET_IDLE_TIMEOUT_MS,\n} from \"./constants.js\";\nimport { formatPerformanceEvent } from \"./perf-utils.js\";\n\n/**\n * Public configuration for the reference plugin wrapper that exposes\n * `FormSpecSemanticService` over the local manifest + IPC transport.\n *\n * Supports the same semantic-service options, including\n * `enablePerformanceLogging`, `performanceLogThresholdMs`, and\n * `snapshotDebounceMs`. The packaged tsserver plugin wires these from\n * `FORMSPEC_PLUGIN_PROFILE=1` and `FORMSPEC_PLUGIN_PROFILE_THRESHOLD_MS`.\n *\n * @public\n */\nexport type FormSpecPluginServiceOptions = FormSpecSemanticServiceOptions;\n\n/**\n * Reference manifest/socket wrapper around `FormSpecSemanticService`.\n *\n * Downstream TypeScript hosts that already control their own plugin/runtime\n * lifecycle can use `FormSpecSemanticService` directly and skip this wrapper.\n *\n * @public\n */\nexport class FormSpecPluginService {\n private readonly manifest: FormSpecAnalysisManifest;\n private readonly runtimePaths: FormSpecWorkspaceRuntimePaths;\n private readonly semanticService: FormSpecSemanticService;\n private server: net.Server | null = null;\n\n public constructor(private readonly options: FormSpecPluginServiceOptions) {\n this.semanticService = new FormSpecSemanticService(options);\n this.runtimePaths = getFormSpecWorkspaceRuntimePaths(options.workspaceRoot);\n this.manifest = createFormSpecAnalysisManifest(\n options.workspaceRoot,\n options.typescriptVersion,\n Date.now()\n );\n }\n\n /**\n * Returns the manifest written by the plugin service for workspace discovery.\n *\n * @internal\n */\n public getManifest(): FormSpecAnalysisManifest {\n return this.manifest;\n }\n\n /**\n * Returns the underlying semantic service used by this reference wrapper.\n *\n * @public\n */\n public getSemanticService(): FormSpecSemanticService {\n return this.semanticService;\n }\n\n /**\n * Starts the IPC transport and writes the current workspace manifest.\n *\n * Calling this more than once is a no-op.\n *\n * @public\n */\n public async start(): Promise<void> {\n if (this.server !== null) {\n return;\n }\n\n await fs.mkdir(this.runtimePaths.runtimeDirectory, { recursive: true });\n if (this.runtimePaths.endpoint.kind === \"unix-socket\") {\n await fs.rm(this.runtimePaths.endpoint.address, { force: true });\n }\n\n this.server = net.createServer((socket) => {\n let buffer = \"\";\n socket.setEncoding(\"utf8\");\n socket.setTimeout(FORM_SPEC_PLUGIN_SOCKET_IDLE_TIMEOUT_MS, () => {\n this.options.logger?.info(\n `[FormSpec] Closing idle semantic query socket for ${this.runtimePaths.workspaceRoot}`\n );\n socket.destroy();\n });\n socket.on(\"data\", (chunk) => {\n buffer += String(chunk);\n if (buffer.length > FORM_SPEC_PLUGIN_MAX_SOCKET_PAYLOAD_BYTES) {\n socket.end(\n `${JSON.stringify({\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"error\",\n error: `FormSpec semantic query exceeded ${String(FORM_SPEC_PLUGIN_MAX_SOCKET_PAYLOAD_BYTES)} bytes`,\n } satisfies FormSpecSemanticResponse)}\\n`\n );\n return;\n }\n\n const newlineIndex = buffer.indexOf(\"\\n\");\n if (newlineIndex < 0) {\n return;\n }\n\n const payload = buffer.slice(0, newlineIndex);\n const remaining = buffer.slice(newlineIndex + 1);\n if (remaining.trim().length > 0) {\n this.options.logger?.info(\n `[FormSpec] Ignoring extra semantic query payload data for ${this.runtimePaths.workspaceRoot}`\n );\n }\n buffer = remaining;\n // The FormSpec IPC transport is intentionally one-request-per-connection.\n this.respondToSocket(socket, payload);\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n const handleError = (error: Error) => {\n reject(error);\n };\n this.server?.once(\"error\", handleError);\n this.server?.listen(this.runtimePaths.endpoint.address, () => {\n this.server?.off(\"error\", handleError);\n resolve();\n });\n });\n\n await this.writeManifest();\n }\n\n /**\n * Stops the IPC transport, clears semantic state, and removes runtime artifacts.\n *\n * @public\n */\n public async stop(): Promise<void> {\n this.semanticService.dispose();\n\n const server = this.server;\n this.server = null;\n if (server?.listening === true) {\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error === undefined) {\n resolve();\n return;\n }\n reject(error);\n });\n });\n }\n\n await this.cleanupRuntimeArtifacts();\n }\n\n /**\n * Schedules a background refresh for the cached semantic snapshot of a file.\n *\n * @public\n */\n public scheduleSnapshotRefresh(filePath: string): void {\n this.semanticService.scheduleSnapshotRefresh(filePath);\n }\n\n /**\n * Handles a semantic query issued against the plugin transport.\n *\n * @internal\n */\n public handleQuery(query: FormSpecSemanticQuery): FormSpecSemanticResponse {\n if (this.options.enablePerformanceLogging === true) {\n const startedAt = performance.now();\n const response = this.executeQuery(query);\n this.logQueryDuration(query, performance.now() - startedAt);\n return response;\n }\n\n return this.executeQuery(query);\n }\n\n private executeQuery(query: FormSpecSemanticQuery): FormSpecSemanticResponse {\n switch (query.kind) {\n case \"health\":\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"health\",\n manifest: this.manifest,\n };\n case \"completion\": {\n const result = this.semanticService.getCompletionContext(query.filePath, query.offset);\n if (result === null) {\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"error\",\n error: `Unable to resolve TypeScript source file for ${query.filePath}`,\n };\n }\n\n return {\n ...result,\n kind: \"completion\",\n };\n }\n case \"hover\": {\n const result = this.semanticService.getHover(query.filePath, query.offset);\n if (result === null) {\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"error\",\n error: `Unable to resolve TypeScript source file for ${query.filePath}`,\n };\n }\n\n return {\n ...result,\n kind: \"hover\",\n };\n }\n case \"diagnostics\": {\n const result = this.semanticService.getDiagnostics(query.filePath);\n return {\n ...result,\n kind: \"diagnostics\",\n };\n }\n case \"file-snapshot\":\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"file-snapshot\",\n snapshot: this.semanticService.getFileSnapshot(query.filePath),\n };\n default: {\n throw new Error(`Unhandled semantic query: ${JSON.stringify(query)}`);\n }\n }\n }\n\n private respondToSocket(socket: net.Socket, payload: string): void {\n try {\n const query = JSON.parse(payload) as unknown;\n if (!isFormSpecSemanticQuery(query)) {\n throw new Error(\"Invalid FormSpec semantic query payload\");\n }\n const response = this.handleQuery(query);\n socket.end(`${JSON.stringify(response)}\\n`);\n } catch (error) {\n socket.end(\n `${JSON.stringify({\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n kind: \"error\",\n error: error instanceof Error ? error.message : String(error),\n } satisfies FormSpecSemanticResponse)}\\n`\n );\n }\n }\n\n private async writeManifest(): Promise<void> {\n const tempManifestPath = `${this.runtimePaths.manifestPath}.tmp`;\n await fs.writeFile(tempManifestPath, `${JSON.stringify(this.manifest, null, 2)}\\n`, \"utf8\");\n await fs.rename(tempManifestPath, this.runtimePaths.manifestPath);\n }\n\n private async cleanupRuntimeArtifacts(): Promise<void> {\n await fs.rm(this.runtimePaths.manifestPath, { force: true });\n\n if (this.runtimePaths.endpoint.kind === \"unix-socket\") {\n await fs.rm(this.runtimePaths.endpoint.address, { force: true });\n }\n }\n\n private logQueryDuration(query: FormSpecSemanticQuery, durationMs: number): void {\n const logger = this.options.logger;\n if (logger === undefined) {\n return;\n }\n\n const thresholdMs =\n this.options.performanceLogThresholdMs ??\n FORM_SPEC_PLUGIN_DEFAULT_PERFORMANCE_LOG_THRESHOLD_MS;\n if (durationMs < thresholdMs) {\n return;\n }\n\n const event: FormSpecPerformanceEvent = {\n name: \"plugin.handleQuery\",\n durationMs,\n detail: {\n kind: query.kind,\n ...(query.kind === \"health\" ? {} : { filePath: query.filePath }),\n },\n };\n logger.info(`[FormSpec][perf] ${formatPerformanceEvent(event)}`);\n }\n}\n\n/**\n * Reference proxy wrapper that keeps FormSpec semantic snapshots fresh while\n * delegating actual TypeScript editor features to the original service.\n *\n * @public\n */\nexport function createLanguageServiceProxy(\n languageService: ts.LanguageService,\n semanticService: FormSpecSemanticService\n): ts.LanguageService {\n const wrapWithSnapshotRefresh = <Args extends readonly unknown[], Result>(\n fn: (fileName: string, ...args: Args) => Result\n ) => {\n return (fileName: string, ...args: Args): Result => {\n semanticService.scheduleSnapshotRefresh(fileName);\n return fn(fileName, ...args);\n };\n };\n\n const getSemanticDiagnostics = wrapWithSnapshotRefresh((fileName) =>\n languageService.getSemanticDiagnostics(fileName)\n );\n\n const getCompletionsAtPosition = wrapWithSnapshotRefresh(\n (fileName: string, position: number, options: ts.GetCompletionsAtPositionOptions | undefined) =>\n languageService.getCompletionsAtPosition(fileName, position, options)\n );\n\n const getQuickInfoAtPosition = wrapWithSnapshotRefresh((fileName, position: number) =>\n languageService.getQuickInfoAtPosition(fileName, position)\n );\n\n return new Proxy(languageService, {\n get(target, property, receiver) {\n switch (property) {\n case \"getSemanticDiagnostics\":\n return getSemanticDiagnostics;\n case \"getCompletionsAtPosition\":\n return getCompletionsAtPosition;\n case \"getQuickInfoAtPosition\":\n return getQuickInfoAtPosition;\n default:\n return Reflect.get(target, property, receiver) as unknown;\n }\n },\n });\n}\n\nexport type { LoggerLike };\n","import os from \"node:os\";\nimport path from \"node:path\";\nimport {\n FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n FORMSPEC_ANALYSIS_SCHEMA_VERSION,\n} from \"@formspec/analysis/protocol\";\nimport {\n getFormSpecManifestPath,\n getFormSpecWorkspaceId,\n getFormSpecWorkspaceRuntimeDirectory,\n type FormSpecAnalysisManifest,\n type FormSpecIpcEndpoint,\n} from \"@formspec/analysis/internal\";\n\nexport interface FormSpecWorkspaceRuntimePaths {\n readonly workspaceRoot: string;\n readonly workspaceId: string;\n readonly runtimeDirectory: string;\n readonly manifestPath: string;\n readonly endpoint: FormSpecIpcEndpoint;\n}\n\nexport function getFormSpecWorkspaceRuntimePaths(\n workspaceRoot: string,\n platform = process.platform,\n userScope = getFormSpecUserScope()\n): FormSpecWorkspaceRuntimePaths {\n const workspaceId = getFormSpecWorkspaceId(workspaceRoot);\n const runtimeDirectory = getFormSpecWorkspaceRuntimeDirectory(workspaceRoot);\n const sanitizedUserScope = sanitizeScopeSegment(userScope);\n const endpoint: FormSpecIpcEndpoint =\n platform === \"win32\"\n ? {\n kind: \"windows-pipe\",\n address: `\\\\\\\\.\\\\pipe\\\\formspec-${sanitizedUserScope}-${workspaceId}`,\n }\n : {\n kind: \"unix-socket\",\n address: path.join(os.tmpdir(), `formspec-${sanitizedUserScope}-${workspaceId}.sock`),\n };\n\n return {\n workspaceRoot,\n workspaceId,\n runtimeDirectory,\n manifestPath: getFormSpecManifestPath(workspaceRoot),\n endpoint,\n };\n}\n\nexport function createFormSpecAnalysisManifest(\n workspaceRoot: string,\n typescriptVersion: string,\n generation: number,\n extensionFingerprint = \"builtin\"\n): FormSpecAnalysisManifest {\n const paths = getFormSpecWorkspaceRuntimePaths(workspaceRoot);\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n analysisSchemaVersion: FORMSPEC_ANALYSIS_SCHEMA_VERSION,\n workspaceRoot,\n workspaceId: paths.workspaceId,\n endpoint: paths.endpoint,\n typescriptVersion,\n extensionFingerprint,\n generation,\n updatedAt: new Date().toISOString(),\n };\n}\n\nfunction getFormSpecUserScope(): string {\n try {\n return sanitizeScopeSegment(os.userInfo().username);\n } catch {\n return sanitizeScopeSegment(\n process.env[\"USER\"] ?? process.env[\"USERNAME\"] ?? process.env[\"LOGNAME\"] ?? \"formspec\"\n );\n }\n}\n\nfunction sanitizeScopeSegment(value: string): string {\n const trimmed = value.trim().toLowerCase();\n const sanitized = trimmed.replace(/[^a-z0-9_-]+/gu, \"-\").replace(/-+/gu, \"-\");\n return sanitized.length > 0 ? sanitized : \"formspec\";\n}\n","import * as ts from \"typescript\";\nimport {\n FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n computeFormSpecTextHash,\n type FormSpecAnalysisDiagnostic,\n type FormSpecAnalysisFileSnapshot,\n type FormSpecSerializedCompletionContext,\n type FormSpecSerializedHoverInfo,\n} from \"@formspec/analysis/protocol\";\nimport {\n buildFormSpecAnalysisFileSnapshot,\n createFormSpecPerformanceRecorder,\n findDeclarationForCommentOffset,\n getCommentHoverInfoAtOffset,\n getSemanticCommentCompletionContextAtOffset,\n getFormSpecPerformanceNow,\n getSubjectType,\n optionalMeasure,\n resolveDeclarationPlacement,\n serializeCompletionContext,\n serializeHoverInfo,\n type BuildFormSpecAnalysisFileSnapshotOptions,\n type FormSpecPerformanceEvent,\n type FormSpecPerformanceRecorder,\n} from \"@formspec/analysis/internal\";\nimport {\n FORM_SPEC_PLUGIN_DEFAULT_PERFORMANCE_LOG_THRESHOLD_MS,\n FORM_SPEC_PLUGIN_DEFAULT_SNAPSHOT_DEBOUNCE_MS,\n} from \"./constants.js\";\nimport { formatPerformanceEvent } from \"./perf-utils.js\";\n\n/**\n * Minimal logging surface used by the semantic service and plugin wrapper.\n *\n * @public\n */\nexport interface LoggerLike {\n /** Writes a human-readable diagnostic or profiling message. */\n info(message: string): void;\n}\n\n/**\n * Configuration for the reusable in-process semantic service.\n *\n * @public\n */\nexport interface FormSpecSemanticServiceOptions {\n /** Workspace root used for runtime paths and contextual logging. */\n readonly workspaceRoot: string;\n /** TypeScript version string reported by the host runtime. */\n readonly typescriptVersion: string;\n /** Supplies the current host program. Returns `undefined` until ready. */\n readonly getProgram: () => ts.Program | undefined;\n /** Optional logger used for profiling and refresh-failure messages. */\n readonly logger?: LoggerLike;\n /** Enables structured hotspot logging for semantic queries. */\n readonly enablePerformanceLogging?: boolean;\n /** Minimum query duration, in milliseconds, required before logging. */\n readonly performanceLogThresholdMs?: number;\n /** Debounce window, in milliseconds, for background snapshot refresh. */\n readonly snapshotDebounceMs?: number;\n /** Injectable clock used by tests and runtime snapshot timestamps. */\n readonly now?: () => Date;\n}\n\n/**\n * Serialized completion result returned by the semantic service.\n *\n * @public\n */\nexport interface FormSpecSemanticCompletionResult {\n /** Protocol version used by the serialized response. */\n readonly protocolVersion: typeof FORMSPEC_ANALYSIS_PROTOCOL_VERSION;\n /** Hash of the source file used to compute the response. */\n readonly sourceHash: string;\n /** Serialized completion payload for the active cursor context. */\n readonly context: FormSpecSerializedCompletionContext;\n}\n\n/**\n * Serialized hover result returned by the semantic service.\n *\n * @public\n */\nexport interface FormSpecSemanticHoverResult {\n /** Protocol version used by the serialized response. */\n readonly protocolVersion: typeof FORMSPEC_ANALYSIS_PROTOCOL_VERSION;\n /** Hash of the source file used to compute the response. */\n readonly sourceHash: string;\n /** Serialized hover payload, or `null` when nothing is available at the cursor. */\n readonly hover: FormSpecSerializedHoverInfo | null;\n}\n\n/**\n * Serialized diagnostics result returned by the semantic service.\n *\n * @public\n */\nexport interface FormSpecSemanticDiagnosticsResult {\n /** Protocol version used by the serialized response. */\n readonly protocolVersion: typeof FORMSPEC_ANALYSIS_PROTOCOL_VERSION;\n /** Hash of the source file used to compute the response. */\n readonly sourceHash: string;\n /** Canonical FormSpec diagnostics for the requested file. */\n readonly diagnostics: readonly FormSpecAnalysisDiagnostic[];\n}\n\n/**\n * Performance and cache counters exposed by the semantic service.\n *\n * @public\n */\nexport interface FormSpecSemanticServiceStats {\n /** Total number of calls by semantic query kind. */\n readonly queryTotals: {\n readonly completion: number;\n readonly hover: number;\n readonly diagnostics: number;\n readonly fileSnapshot: number;\n };\n /** Cold vs warm query path counts for snapshot-backed operations. */\n readonly queryPathTotals: {\n readonly diagnostics: { readonly cold: number; readonly warm: number };\n readonly fileSnapshot: { readonly cold: number; readonly warm: number };\n };\n /** Number of file snapshot cache hits. */\n readonly fileSnapshotCacheHits: number;\n /** Number of file snapshot cache misses. */\n readonly fileSnapshotCacheMisses: number;\n /** Number of synthetic batch cache hits. */\n readonly syntheticBatchCacheHits: number;\n /** Number of synthetic batch cache misses. */\n readonly syntheticBatchCacheMisses: number;\n /** Number of synthetic compiler program creations. */\n readonly syntheticCompileCount: number;\n /** Total synthetic application count compiled across misses. */\n readonly syntheticCompileApplications: number;\n}\n\ninterface CachedFileSnapshot {\n readonly sourceHash: string;\n readonly snapshot: FormSpecAnalysisFileSnapshot;\n}\n\ninterface SourceEnvironment {\n readonly sourceFile: ts.SourceFile;\n readonly checker: ts.TypeChecker;\n readonly sourceHash: string;\n}\n\ninterface CommentQueryContext extends SourceEnvironment {\n readonly declaration: ts.Node | null;\n readonly placement: ReturnType<typeof resolveDeclarationPlacement>;\n readonly subjectType: ts.Type | undefined;\n}\n\ntype SnapshotCacheState = \"hit\" | \"miss\" | \"missing-source\";\n\ninterface MutableSemanticServiceStats {\n queryTotals: {\n completion: number;\n hover: number;\n diagnostics: number;\n fileSnapshot: number;\n };\n queryPathTotals: {\n diagnostics: { cold: number; warm: number };\n fileSnapshot: { cold: number; warm: number };\n };\n fileSnapshotCacheHits: number;\n fileSnapshotCacheMisses: number;\n syntheticBatchCacheHits: number;\n syntheticBatchCacheMisses: number;\n syntheticCompileCount: number;\n syntheticCompileApplications: number;\n}\n\nconst STATS_ONLY_EVENT_NAMES = new Set<string>([\n \"analysis.syntheticCheckBatch.cacheHit\",\n \"analysis.narrowSyntheticCheckBatch.cacheHit\",\n \"analysis.syntheticCheckBatch.cacheMiss\",\n \"analysis.narrowSyntheticCheckBatch.cacheMiss\",\n \"analysis.syntheticCheckBatch.createProgram\",\n \"analysis.narrowSyntheticCheckBatch.createProgram\",\n]);\n\nclass StatsOnlyPerformanceRecorder implements FormSpecPerformanceRecorder {\n private readonly mutableEvents: FormSpecPerformanceEvent[] = [];\n\n public get events(): readonly FormSpecPerformanceEvent[] {\n return this.mutableEvents;\n }\n\n public measure<T>(\n name: string,\n detail: Readonly<Record<string, string | number | boolean>> | undefined,\n callback: () => T\n ): T {\n const result = callback();\n if (STATS_ONLY_EVENT_NAMES.has(name)) {\n this.mutableEvents.push({\n name,\n durationMs: 0,\n ...(detail === undefined ? {} : { detail }),\n });\n }\n return result;\n }\n\n public record(event: FormSpecPerformanceEvent): void {\n if (STATS_ONLY_EVENT_NAMES.has(event.name)) {\n this.mutableEvents.push(event);\n }\n }\n}\n/**\n * Reusable in-process semantic service for FormSpec authoring features.\n *\n * Downstream TypeScript hosts can construct this directly against their own\n * `Program` and own the final presentation of completions, hover, and\n * diagnostics. The shipped tsserver plugin is a reference wrapper over this\n * public service.\n *\n * @public\n */\nexport class FormSpecSemanticService {\n private readonly snapshotCache = new Map<string, CachedFileSnapshot>();\n private readonly refreshTimers = new Map<string, NodeJS.Timeout>();\n private readonly stats: MutableSemanticServiceStats = {\n queryTotals: {\n completion: 0,\n hover: 0,\n diagnostics: 0,\n fileSnapshot: 0,\n },\n queryPathTotals: {\n diagnostics: { cold: 0, warm: 0 },\n fileSnapshot: { cold: 0, warm: 0 },\n },\n fileSnapshotCacheHits: 0,\n fileSnapshotCacheMisses: 0,\n syntheticBatchCacheHits: 0,\n syntheticBatchCacheMisses: 0,\n syntheticCompileCount: 0,\n syntheticCompileApplications: 0,\n };\n\n public constructor(private readonly options: FormSpecSemanticServiceOptions) {}\n\n /** Resolves semantic completion context for a comment cursor position. */\n public getCompletionContext(\n filePath: string,\n offset: number\n ): FormSpecSemanticCompletionResult | null {\n this.stats.queryTotals.completion += 1;\n return this.runMeasured(\"semantic.getCompletionContext\", { filePath, offset }, (performance) =>\n this.withCommentQueryContext(filePath, offset, performance, (context) => ({\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n sourceHash: context.sourceHash,\n context: serializeCompletionContext(\n getSemanticCommentCompletionContextAtOffset(context.sourceFile.text, offset, {\n checker: context.checker,\n ...(context.placement === null ? {} : { placement: context.placement }),\n ...(context.subjectType === undefined ? {} : { subjectType: context.subjectType }),\n })\n ),\n }))\n );\n }\n\n /** Resolves semantic hover payload for a comment cursor position. */\n public getHover(filePath: string, offset: number): FormSpecSemanticHoverResult | null {\n this.stats.queryTotals.hover += 1;\n return this.runMeasured(\"semantic.getHover\", { filePath, offset }, (performance) =>\n this.withCommentQueryContext(filePath, offset, performance, (context) => ({\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n sourceHash: context.sourceHash,\n hover: serializeHoverInfo(\n getCommentHoverInfoAtOffset(context.sourceFile.text, offset, {\n checker: context.checker,\n ...(context.placement === null ? {} : { placement: context.placement }),\n ...(context.subjectType === undefined ? {} : { subjectType: context.subjectType }),\n })\n ),\n }))\n );\n }\n\n /** Returns canonical FormSpec diagnostics for a file in the current host program. */\n public getDiagnostics(filePath: string): FormSpecSemanticDiagnosticsResult {\n this.stats.queryTotals.diagnostics += 1;\n return this.runMeasured(\"semantic.getDiagnostics\", { filePath }, (performance) => {\n const { snapshot, cacheState } = this.getFileSnapshotWithCacheState(filePath, performance);\n this.recordQueryPath(\"diagnostics\", cacheState);\n return {\n protocolVersion: FORMSPEC_ANALYSIS_PROTOCOL_VERSION,\n sourceHash: snapshot.sourceHash,\n diagnostics: snapshot.diagnostics,\n };\n });\n }\n\n /** Returns the full serialized semantic snapshot for a file. */\n public getFileSnapshot(filePath: string): FormSpecAnalysisFileSnapshot {\n this.stats.queryTotals.fileSnapshot += 1;\n return this.runMeasured(\"semantic.getFileSnapshot\", { filePath }, (performance) => {\n const { snapshot, cacheState } = this.getFileSnapshotWithCacheState(filePath, performance);\n this.recordQueryPath(\"fileSnapshot\", cacheState);\n return snapshot;\n });\n }\n\n /** Schedules a debounced background refresh for the file snapshot cache. */\n public scheduleSnapshotRefresh(filePath: string): void {\n const existing = this.refreshTimers.get(filePath);\n if (existing !== undefined) {\n clearTimeout(existing);\n }\n\n const timer = setTimeout(() => {\n try {\n this.getFileSnapshot(filePath);\n } catch (error: unknown) {\n this.options.logger?.info(\n `[FormSpec] Failed to refresh semantic snapshot for ${filePath}: ${String(error)}`\n );\n }\n this.refreshTimers.delete(filePath);\n }, this.options.snapshotDebounceMs ?? FORM_SPEC_PLUGIN_DEFAULT_SNAPSHOT_DEBOUNCE_MS);\n timer.unref();\n\n this.refreshTimers.set(filePath, timer);\n }\n\n /** Clears pending timers and cached semantic snapshots. */\n public dispose(): void {\n for (const timer of this.refreshTimers.values()) {\n clearTimeout(timer);\n }\n this.refreshTimers.clear();\n this.snapshotCache.clear();\n }\n\n /** Returns a copy of the current performance and cache counters. */\n public getStats(): FormSpecSemanticServiceStats {\n return {\n queryTotals: { ...this.stats.queryTotals },\n queryPathTotals: {\n diagnostics: { ...this.stats.queryPathTotals.diagnostics },\n fileSnapshot: { ...this.stats.queryPathTotals.fileSnapshot },\n },\n fileSnapshotCacheHits: this.stats.fileSnapshotCacheHits,\n fileSnapshotCacheMisses: this.stats.fileSnapshotCacheMisses,\n syntheticBatchCacheHits: this.stats.syntheticBatchCacheHits,\n syntheticBatchCacheMisses: this.stats.syntheticBatchCacheMisses,\n syntheticCompileCount: this.stats.syntheticCompileCount,\n syntheticCompileApplications: this.stats.syntheticCompileApplications,\n };\n }\n\n private runMeasured<T>(\n name: string,\n detail: Record<string, string | number>,\n fn: (performance: FormSpecPerformanceRecorder) => T\n ): T {\n const performance =\n this.options.enablePerformanceLogging === true\n ? createFormSpecPerformanceRecorder()\n : new StatsOnlyPerformanceRecorder();\n const result = optionalMeasure(performance, name, detail, () => fn(performance));\n this.updateStatsFromPerformanceEvents(performance.events);\n if (this.options.enablePerformanceLogging === true) {\n this.logPerformanceEvents(name, performance.events);\n }\n return result;\n }\n\n private withCommentQueryContext<T>(\n filePath: string,\n offset: number,\n performance: FormSpecPerformanceRecorder,\n handler: (context: CommentQueryContext) => T\n ): T | null {\n return optionalMeasure(\n performance,\n \"semantic.resolveCommentQueryContext\",\n {\n filePath,\n offset,\n },\n () => {\n const environment = this.getSourceEnvironment(filePath, performance);\n if (environment === null) {\n return null;\n }\n\n const declaration = optionalMeasure(\n performance,\n \"semantic.findDeclarationForCommentOffset\",\n {\n filePath,\n offset,\n },\n () => findDeclarationForCommentOffset(environment.sourceFile, offset)\n );\n const placement =\n declaration === null\n ? null\n : optionalMeasure(performance, \"semantic.resolveDeclarationPlacement\", undefined, () =>\n resolveDeclarationPlacement(declaration)\n );\n const subjectType =\n declaration === null\n ? undefined\n : optionalMeasure(performance, \"semantic.getSubjectType\", undefined, () =>\n getSubjectType(declaration, environment.checker)\n );\n\n return handler({\n ...environment,\n declaration,\n placement,\n subjectType,\n });\n }\n );\n }\n\n private getFileSnapshotWithCacheState(\n filePath: string,\n performance: FormSpecPerformanceRecorder\n ): {\n readonly snapshot: FormSpecAnalysisFileSnapshot;\n readonly cacheState: SnapshotCacheState;\n } {\n const startedAt = getFormSpecPerformanceNow();\n const environment = this.getSourceEnvironment(filePath, performance);\n if (environment === null) {\n this.stats.fileSnapshotCacheMisses += 1;\n const snapshot: FormSpecAnalysisFileSnapshot = {\n filePath,\n sourceHash: \"\",\n generatedAt: this.getNow().toISOString(),\n comments: [],\n diagnostics: [\n {\n code: \"MISSING_SOURCE_FILE\",\n category: \"infrastructure\",\n message: `Unable to resolve TypeScript source file for ${filePath}`,\n range: { start: 0, end: 0 },\n severity: \"warning\",\n relatedLocations: [],\n data: {\n filePath,\n },\n },\n ],\n };\n performance.record({\n name: \"semantic.getFileSnapshot.result\",\n durationMs: getFormSpecPerformanceNow() - startedAt,\n detail: {\n filePath,\n cache: \"missing-source\",\n },\n });\n return {\n snapshot,\n cacheState: \"missing-source\",\n };\n }\n\n const cached = this.snapshotCache.get(filePath);\n if (cached?.sourceHash === environment.sourceHash) {\n this.stats.fileSnapshotCacheHits += 1;\n performance.record({\n name: \"semantic.getFileSnapshot.result\",\n durationMs: getFormSpecPerformanceNow() - startedAt,\n detail: {\n filePath,\n cache: \"hit\",\n },\n });\n return {\n snapshot: cached.snapshot,\n cacheState: \"hit\",\n };\n }\n\n this.stats.fileSnapshotCacheMisses += 1;\n const snapshot = buildFormSpecAnalysisFileSnapshot(environment.sourceFile, {\n checker: environment.checker,\n now: () => this.getNow(),\n performance,\n } satisfies BuildFormSpecAnalysisFileSnapshotOptions);\n this.snapshotCache.set(filePath, {\n sourceHash: environment.sourceHash,\n snapshot,\n });\n performance.record({\n name: \"semantic.getFileSnapshot.result\",\n durationMs: getFormSpecPerformanceNow() - startedAt,\n detail: {\n filePath,\n cache: \"miss\",\n },\n });\n return {\n snapshot,\n cacheState: \"miss\",\n };\n }\n\n private getNow(): Date {\n return this.options.now?.() ?? new Date();\n }\n\n private getSourceEnvironment(\n filePath: string,\n performance: FormSpecPerformanceRecorder\n ): SourceEnvironment | null {\n return optionalMeasure(\n performance,\n \"semantic.getSourceEnvironment\",\n {\n filePath,\n },\n () => {\n const program = optionalMeasure(\n performance,\n \"semantic.sourceEnvironment.getProgram\",\n undefined,\n () => this.options.getProgram()\n );\n if (program === undefined) {\n return null;\n }\n\n const sourceFile = optionalMeasure(\n performance,\n \"semantic.sourceEnvironment.getSourceFile\",\n undefined,\n () => program.getSourceFile(filePath)\n );\n if (sourceFile === undefined) {\n return null;\n }\n\n const checker = optionalMeasure(\n performance,\n \"semantic.sourceEnvironment.getTypeChecker\",\n undefined,\n () => program.getTypeChecker()\n );\n const sourceHash = optionalMeasure(\n performance,\n \"semantic.sourceEnvironment.computeTextHash\",\n undefined,\n () => computeFormSpecTextHash(sourceFile.text)\n );\n\n return {\n sourceFile,\n checker,\n sourceHash,\n };\n }\n );\n }\n\n private recordQueryPath(\n kind: \"diagnostics\" | \"fileSnapshot\",\n cacheState: SnapshotCacheState\n ): void {\n if (cacheState === \"hit\") {\n this.stats.queryPathTotals[kind].warm += 1;\n return;\n }\n\n this.stats.queryPathTotals[kind].cold += 1;\n }\n\n private updateStatsFromPerformanceEvents(events: readonly FormSpecPerformanceEvent[]): void {\n for (const event of events) {\n if (\n event.name === \"analysis.syntheticCheckBatch.cacheHit\" ||\n event.name === \"analysis.narrowSyntheticCheckBatch.cacheHit\"\n ) {\n this.stats.syntheticBatchCacheHits += 1;\n continue;\n }\n\n if (\n event.name === \"analysis.syntheticCheckBatch.cacheMiss\" ||\n event.name === \"analysis.narrowSyntheticCheckBatch.cacheMiss\"\n ) {\n this.stats.syntheticBatchCacheMisses += 1;\n const applicationCount = event.detail?.[\"applicationCount\"];\n if (typeof applicationCount === \"number\") {\n this.stats.syntheticCompileApplications += applicationCount;\n }\n continue;\n }\n\n if (\n event.name === \"analysis.syntheticCheckBatch.createProgram\" ||\n event.name === \"analysis.narrowSyntheticCheckBatch.createProgram\"\n ) {\n this.stats.syntheticCompileCount += 1;\n }\n }\n }\n\n private logPerformanceEvents(\n rootEventName: string,\n events: readonly FormSpecPerformanceEvent[]\n ): void {\n const logger = this.options.logger;\n if (logger === undefined || events.length === 0) {\n return;\n }\n\n const rootEvent = [...events].reverse().find((event) => event.name === rootEventName);\n if (rootEvent === undefined) {\n return;\n }\n\n const thresholdMs =\n this.options.performanceLogThresholdMs ??\n FORM_SPEC_PLUGIN_DEFAULT_PERFORMANCE_LOG_THRESHOLD_MS;\n if (rootEvent.durationMs < thresholdMs) {\n return;\n }\n\n const sortedHotspots = [...events]\n .filter((event) => event.name !== rootEventName)\n .sort((left, right) => right.durationMs - left.durationMs)\n .slice(0, 8);\n const lines = [\n `[FormSpec][perf] ${formatPerformanceEvent(rootEvent)}`,\n ...sortedHotspots.map((event) => ` ${formatPerformanceEvent(event)}`),\n ];\n logger.info(lines.join(\"\\n\"));\n }\n}\n","export const FORM_SPEC_PLUGIN_MAX_SOCKET_PAYLOAD_BYTES = 256 * 1024;\nexport const FORM_SPEC_PLUGIN_SOCKET_IDLE_TIMEOUT_MS = 30_000;\nexport const FORM_SPEC_PLUGIN_DEFAULT_PERFORMANCE_LOG_THRESHOLD_MS = 50;\nexport const FORM_SPEC_PLUGIN_DEFAULT_SNAPSHOT_DEBOUNCE_MS = 250;\n\nexport const FORM_SPEC_PLUGIN_PERFORMANCE_EVENT = {\n handleQuery: \"plugin.handleQuery\",\n} as const;\n","import type { FormSpecPerformanceEvent } from \"@formspec/analysis/internal\";\n\nexport function formatPerformanceEvent(event: FormSpecPerformanceEvent): string {\n const detailEntries = Object.entries(event.detail ?? {})\n .map(([key, value]) => `${key}=${String(value)}`)\n .join(\" \");\n return `${event.durationMs.toFixed(1)}ms ${event.name}${detailEntries === \"\" ? \"\" : ` ${detailEntries}`}`;\n}\n"],"mappings":"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","names":["import_protocol","ts","import_protocol","import_internal","path","os","import_protocol","import_internal","performance","snapshot","fs","net"]}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,13 @@
1
+ /**
2
+ * TypeScript language service plugin entrypoint for FormSpec.
3
+ *
4
+ * This package exposes the reference tsserver plugin and the reusable semantic
5
+ * service used by downstream TypeScript hosts.
6
+ *
7
+ * @packageDocumentation
8
+ */
1
9
  import type * as tsServer from "typescript/lib/tsserverlibrary.js";
2
- export { FORMSPEC_ANALYSIS_PROTOCOL_VERSION, FORMSPEC_ANALYSIS_SCHEMA_VERSION, type CommentSourceSpan, type CommentSpan, type FormSpecAnalysisCommentSnapshot, type FormSpecAnalysisDiagnostic, type FormSpecAnalysisDiagnosticCategory, type FormSpecAnalysisDiagnosticDataValue, type FormSpecAnalysisDiagnosticLocation, type FormSpecAnalysisManifest, type FormSpecAnalysisFileSnapshot, type FormSpecAnalysisTagSnapshot, type FormSpecIpcEndpoint, type FormSpecPlacement, type FormSpecSemanticQuery, type FormSpecSemanticResponse, type FormSpecSerializedCommentTargetSpecifier, type FormSpecSerializedCompletionContext, type FormSpecSerializedHoverInfo, type FormSpecSerializedTagDefinition, type FormSpecSerializedTagSemanticContext, type FormSpecSerializedTagSignature, type FormSpecTargetKind, } from "@formspec/analysis/protocol";
10
+ export { FORMSPEC_ANALYSIS_PROTOCOL_VERSION, FORMSPEC_ANALYSIS_SCHEMA_VERSION, type CommentHoverInfo, type CommentSourceSpan, type CommentSpan, type FormSpecAnalysisCommentSnapshot, type FormSpecAnalysisDiagnostic, type FormSpecAnalysisDiagnosticCategory, type FormSpecAnalysisDiagnosticDataValue, type FormSpecAnalysisDiagnosticLocation, type FormSpecAnalysisFileSnapshot, type FormSpecAnalysisTagSnapshot, type FormSpecPlacement, type FormSpecTargetKind, type FormSpecSerializedCommentTargetSpecifier, type FormSpecSerializedCompletionContext, type FormSpecSerializedHoverInfo, type FormSpecSerializedTagDefinition, type FormSpecSerializedTagSemanticContext, type FormSpecSerializedTagSignature, } from "@formspec/analysis/protocol";
3
11
  export { createLanguageServiceProxy, FormSpecPluginService, type FormSpecPluginServiceOptions, type LoggerLike, } from "./service.js";
4
12
  export { FormSpecSemanticService, type FormSpecSemanticCompletionResult, type FormSpecSemanticDiagnosticsResult, type FormSpecSemanticHoverResult, type FormSpecSemanticServiceOptions, type FormSpecSemanticServiceStats, } from "./semantic-service.js";
5
13
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,QAAQ,MAAM,mCAAmC,CAAC;AACnE,OAAO,EACL,kCAAkC,EAClC,gCAAgC,EAChC,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,+BAA+B,EACpC,KAAK,0BAA0B,EAC/B,KAAK,kCAAkC,EACvC,KAAK,mCAAmC,EACxC,KAAK,kCAAkC,EACvC,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAChC,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,wCAAwC,EAC7C,KAAK,mCAAmC,EACxC,KAAK,2BAA2B,EAChC,KAAK,+BAA+B,EACpC,KAAK,oCAAoC,EACzC,KAAK,8BAA8B,EACnC,KAAK,kBAAkB,GACxB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,KAAK,UAAU,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,uBAAuB,EACvB,KAAK,gCAAgC,EACrC,KAAK,iCAAiC,EACtC,KAAK,2BAA2B,EAChC,KAAK,8BAA8B,EACnC,KAAK,4BAA4B,GAClC,MAAM,uBAAuB,CAAC;AAgG/B;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE;IAC5B,QAAQ,CAAC,UAAU,EAAE,OAAO,QAAQ,CAAC;CACtC,GAAG,QAAQ,CAAC,MAAM,CAAC,YAAY,CAQ/B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,KAAK,QAAQ,MAAM,mCAAmC,CAAC;AACnE,OAAO,EACL,kCAAkC,EAClC,gCAAgC,EAChC,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,+BAA+B,EACpC,KAAK,0BAA0B,EAC/B,KAAK,kCAAkC,EACvC,KAAK,mCAAmC,EACxC,KAAK,kCAAkC,EACvC,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAChC,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,wCAAwC,EAC7C,KAAK,mCAAmC,EACxC,KAAK,2BAA2B,EAChC,KAAK,+BAA+B,EACpC,KAAK,oCAAoC,EACzC,KAAK,8BAA8B,GACpC,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,KAAK,UAAU,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,uBAAuB,EACvB,KAAK,gCAAgC,EACrC,KAAK,iCAAiC,EACtC,KAAK,2BAA2B,EAChC,KAAK,8BAA8B,EACnC,KAAK,4BAA4B,GAClC,MAAM,uBAAuB,CAAC;AAgG/B;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE;IAC5B,QAAQ,CAAC,UAAU,EAAE,OAAO,QAAQ,CAAC;CACtC,GAAG,QAAQ,CAAC,MAAM,CAAC,YAAY,CAQ/B"}
package/dist/index.js CHANGED
@@ -9,10 +9,11 @@ import fs from "fs/promises";
9
9
  import net from "net";
10
10
  import "typescript";
11
11
  import {
12
- FORMSPEC_ANALYSIS_PROTOCOL_VERSION as FORMSPEC_ANALYSIS_PROTOCOL_VERSION3,
13
- isFormSpecSemanticQuery
12
+ FORMSPEC_ANALYSIS_PROTOCOL_VERSION as FORMSPEC_ANALYSIS_PROTOCOL_VERSION3
14
13
  } from "@formspec/analysis/protocol";
15
- import "@formspec/analysis/internal";
14
+ import {
15
+ isFormSpecSemanticQuery
16
+ } from "@formspec/analysis/internal";
16
17
 
17
18
  // src/workspace.ts
18
19
  import os from "os";
@@ -505,6 +506,11 @@ var FormSpecPluginService = class {
505
506
  runtimePaths;
506
507
  semanticService;
507
508
  server = null;
509
+ /**
510
+ * Returns the manifest written by the plugin service for workspace discovery.
511
+ *
512
+ * @internal
513
+ */
508
514
  getManifest() {
509
515
  return this.manifest;
510
516
  }
@@ -516,6 +522,13 @@ var FormSpecPluginService = class {
516
522
  getSemanticService() {
517
523
  return this.semanticService;
518
524
  }
525
+ /**
526
+ * Starts the IPC transport and writes the current workspace manifest.
527
+ *
528
+ * Calling this more than once is a no-op.
529
+ *
530
+ * @public
531
+ */
519
532
  async start() {
520
533
  if (this.server !== null) {
521
534
  return;
@@ -573,6 +586,11 @@ var FormSpecPluginService = class {
573
586
  });
574
587
  await this.writeManifest();
575
588
  }
589
+ /**
590
+ * Stops the IPC transport, clears semantic state, and removes runtime artifacts.
591
+ *
592
+ * @public
593
+ */
576
594
  async stop() {
577
595
  this.semanticService.dispose();
578
596
  const server = this.server;
@@ -590,9 +608,19 @@ var FormSpecPluginService = class {
590
608
  }
591
609
  await this.cleanupRuntimeArtifacts();
592
610
  }
611
+ /**
612
+ * Schedules a background refresh for the cached semantic snapshot of a file.
613
+ *
614
+ * @public
615
+ */
593
616
  scheduleSnapshotRefresh(filePath) {
594
617
  this.semanticService.scheduleSnapshotRefresh(filePath);
595
618
  }
619
+ /**
620
+ * Handles a semantic query issued against the plugin transport.
621
+ *
622
+ * @internal
623
+ */
596
624
  handleQuery(query) {
597
625
  if (this.options.enablePerformanceLogging === true) {
598
626
  const startedAt = performance.now();