Prisma Language Tools

repository·main·Indexed 43 days ago

https://github.com/prisma/language-tools

Core language intelligence for Prisma schema files, featuring a Language Server Protocol (LSP) implementation and a VS Code extension. Provides IDE features for .prisma files including diagnostics, completions, formatting, and renaming, as well as integration with Prisma Studio and Prisma Postgres.

Tokens
23.4K
Snippets
67
Records
111
Agent score
54%

What's inside Prisma Language Tools

  1. Overview of Prisma Language Tools

    main

    Prisma Language Tools provides the VS Code extension and Language Server Protocol (LSP) implementation for Prisma schema files. It enables advanced editor features like syntax highlighting, autocompletion, and validation for .prisma files.

    There are two main distribution channels:

    • Prisma (stable): The standard production version.
    • Prisma Insider (preview): A preview version for testing upcoming features.
  2. Features of the Prisma VS Code Extension

    main

    The Prisma VS Code extension provides several developer productivity features for working with Prisma schemas:

    • Syntax Highlighting: Visual comprehension of the Prisma schema.
    • Formatting: Ensures consistent indentation of models for better readability.
    • Linting and Autocompletion: Shows inline errors in the schema and assists in defining correct types.
    • Contextual Suggestions: Assists in defining field types, models, and relations. It also automatically defines back relations during formatting.
    • Jump-to-definition: Allows easy navigation to model definitions within the Prisma schema.
  3. Features of the Prisma Language Server

    main

    The Prisma Language Server provides the following IDE features for .prisma files:

    • Diagnostics: Real-time error and warning highlighting.
    • Completions: Context-aware suggestions for keywords, types, and attributes.
    • Hover: Documentation on hover for models, fields, and attributes.
    • Go to Definition: Jump to model or enum definitions.
    • Document Formatting: Format .prisma files.
    • Code Actions: Quick fixes for common issues.
    • Rename: Rename models, enums, or fields with automatic @map handling.
    • Document Symbols: Provides an outline view of models, enums, and generators.
    • References: Find all usages of a specific model or enum.
  4. How the VS Code Extension Plugin System works

    main

    The Prisma VS Code extension utilizes a plugin architecture to modularize functionality. Each plugin must implement the PrismaVSCodePlugin interface, which defines how the plugin is identified, whether it should be active, and its lifecycle hooks for activation and deactivation. This allows the extension to manage features like the Language Server Protocol (LSP) client, database management, and AI tools as independent modules.

    // packages/vscode/src/plugins/types.ts
    interface PrismaVSCodePlugin {
      name: string
      enabled: () => Promise<boolean> | boolean
      activate?: (context: ExtensionContext) => Promise<void> | void
      deactivate?: () => Promise<void> | void
    }
  5. Understand worker process behavior

    main
    To prevent blocking the VS Code extension host, long-running tasks (such as the local Prisma Postgres server) are executed in forked child processes. This ensures the editor remains responsive while these background services are running.
  6. Add new completions

    main

    Completions in this project are derived from two distinct sources:

    1. WASM-based completions: Provided by prisma-schema-wasm via prismaSchemaWasmCompletions.
    2. Local TypeScript completions: Managed via localCompletions. Implementation details for local completions can be found in packages/language-server/src/lib/completions/.
  7. Understand the VS Code extension build system

    main
    The VS Code extension uses esbuild to bundle code into optimized CommonJS modules targeting Node.js 20. Bundling is necessary because the extension host only supports npm and yarn for dependency resolution, whereas this project uses pnpm. Bundling inlines dependencies to avoid runtime failures caused by pnpm's symlink-based node_modules structure.
  8. How VS Code document routing and directives work

    main

    The language server uses directives at the start of a .prisma file to determine which server handles the document.

    Directives

    • // use prisma-next
    • // use prisma-8

    Both directives are equivalent. They must appear at the start of the file (whitespace is allowed before them).

    Routing Logic

    When prisma.pinToPrisma6 is disabled:

    1. Legacy Server: Used if neither directive is present.
    2. Prisma Next Server: Used if a directive is present, the file is in a trusted workspace, the root matches, and the Prisma Next CLI is available. The extension starts at most one Prisma Next server per workspace root.
    3. No Features: Used if a directive is present but Prisma Next execution is ineligible or unavailable.

    If prisma.pinToPrisma6 is enabled, every Prisma document is routed to the legacy Prisma 6 server.

    Important Notes

    • Per-file scope: A directive only applies to the file it is in; it does not automatically opt in sibling files or the rest of a multi-file schema.
    • CLI Requirement: For marked files, the extension uses the Prisma CLI located at <workspace-root>/node_modules/prisma/dist/prisma.js. It will not search parent directories or use a global installation.
    • Dynamic Switching: Adding or removing a directive in an open file switches the handler immediately without requiring a save or restart.
  9. How local Prisma Postgres (ppg dev) is handled in the extension

    main

    The Prisma VS Code extension supports running local Prisma Postgres instances via @prisma/dev. To prevent long-running database processes from blocking the VS Code extension host, these instances run in a separate forked process.

    Architecture Overview

    1. Extension Host: Calls PrismaDevRepository.startInstance().
    2. Forked Worker: A separate process running the bundled dist/workers/ppgDevServer.js.
    3. Server: The worker starts the @prisma/dev server, which internally uses @electric-sql/pglite.

    Worker Lifecycle

    The worker (defined in src/workers/ppgDevServer.ts) follows this lifecycle:

    • Receives the database name as a CLI argument.
    • Starts the @prisma/dev server using unstable_startServer with persistenceMode: 'stateful'.
    • Communicates its status back to the extension host via IPC (process.send()).
    • Handles graceful shutdown upon receiving SIGTERM or SIGINT signals.
  10. Understand the Prisma VS Code Extension Architecture

    main

    The Prisma VS Code extension is composed of several specialized plugins that communicate with different backend services. The core architecture consists of:

    • Language Server Plugin: Communicates with the Language Server (packages/language-server) via LSP over IPC. The language server uses a MessageHandler to dispatch requests and relies on the prisma-schema-wasm module for parsing, formatting, and linting.
    • Prisma Postgres Manager: Manages local and remote Postgres instances. It uses HTTP to communicate with the Prisma HTTP API and can fork() a PPG Dev Server Worker.
    • Prisma Studio Plugin: Provides the Prisma Studio UI via a webview using HTTP.
    • AI Tools Plugin: Provides AI-driven capabilities via HTTP (webview).

    The PPG Dev Server Worker (dist/workers/ppgDevServer.js) runs as a detached process using IPC communication. It hosts a local PPG server via @prisma/dev and can use pglite for an in-process PostgreSQL experience. This worker is designed to survive extension restarts.

    ┌────────────────────────────────────────────────────────────────────────────┐
    │                           VS Code Extension                                │
    │  packages/vscode/src/extension.ts                                          │
    │                                                                            │
    │  ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌───────────┐ │
    │  │ Language Server │ │ Prisma Postgres │ │  Prisma Studio  │ │ AI Tools   │ │
    │  │     Plugin      │ │     Manager     │ │     Plugin      │ │  Plugin   │ │
    │  └────────┬────────┘ └────────┬─────┬──┘ └───────────────┬─┘ └───────────┘ │
    │           │              HTTP │     │                    │                 │
    │           │ LSP over IPC     │     │ fork()             │ HTTP (webview)   │
    └───────────┼───────────────────┼─────────────────────────┼─────────────────┘
                │                   │     │                    │                 │
                │                   │     │                    └─────────────┐    ┌─┴──────────────────────┐
                ▼                   ▼     │                                   ▼    ▼                        ▼
    ┌───────────────────────────┐  ┌ ─ ─ ─ ─ ─ ┐  ┌─────────────────────────┐  ┌ ─ ─ ─ ─ ─ ─ ─ ┐
    │      Language Server      │      Prisma │  │   PPG Dev Server Worker │  │    Remote Prisma  │
    │  packages/language-server │      HTTP   │  │   dist/workers/         │  │      (Cloud)      │
    │  /src/server.ts           │      API   │  │   ppgDevServer.js       │  │                   │
    │                           │  └ ─ ─ ─ ─ ┘  │                         │  └ ─ ─ ─ ─ ─ ─ ─ ─ ┘
    │  ┌─────────────────────┐  │                 │  ┌───────────────────┐  │
    │  │    MessageHandler   │  │                 │  │    @prisma/dev    │  │
    │  │  Dispatches LSP     │  │                 │  │  Local PPG server │  │
    │  └──────────┬──────────┘  │                 │  │                   │  │
    │             │             │                 │  │  ┌─────────────┐  │  │
    │             ▼             │                 │  │  │   pglite    │  │  │
    │  ┌─────────────────────┐  │                 │  │  │  In-process │  │  │
    │  │ prisma-schema-wasm  │  │                 │  │  │  PostgreSQL │  │  │
    │  │  WASM module for    │  │                 │  │  └─────────────┘  │  │
    │  │ parsing/formatting │  │                 │  └───────────────────┘  │
    │  └─────────────────────┘  │                 │                         │
    └───────────────────────────┘                 │  • Detached process     │
                                                    │  • IPC communication    │
                                                    │  • Survives restarts    │
                                                    └─────────────────────────┘
  11. How multi-file schema support works in the language server

    main

    Prisma supports splitting schemas across multiple .prisma files. The PrismaSchema class is used to manage these files as a single logical schema. You can load a schema by providing the current document and a collection of all available documents, and then iterate over all lines across all files in the schema using iterLines().

    // Loading a schema (handles both single and multi-file)
    const schema = await PrismaSchema.load({
      currentDocument: textDocument,
      allDocuments: documents.all(),
    })
    
    // Iterating over all lines across files
    for (const line of schema.iterLines()) {
      // line.document, line.lineIndex, line.text
    }
  12. Use the cursor position convention in Language Server tests

    main

    When writing Language Server unit tests, use the | (pipe) character within fixture files to indicate the cursor position. The findCursorPosition() helper is used to extract this position for testing completions and other editor-state dependent features.

    // In test fixture files, | marks where the cursor is
    const schema = `
    model User {
      id Int @id
      name Str|  // cursor is here, testing completion
    }
    `