Files
volar-docs/docs/cli-integration.md
2025-11-09 22:22:52 -06:00

5.0 KiB
Raw Permalink Blame History

CLI Integration & Headless Workflows

Docs IndexRepo READMEWorkspace DiagnosticsTesting & CILSP Benchmarking

Language intelligence isnt limited to editors—teams often run Volar-powered checks in CI, pre-commit hooks, or bespoke tooling. This guide shows how to build CLI utilities (à la vue-tsc) that reuse your Volar language service for headless diagnostics, formatting, or codegen tasks.

Approaches

Approach Pros Cons
Reuse vue-tsc Fast to adopt, maintained by Vue team Limited to diagnostics; less customizable
Custom CLI (Node) Full control, integrate custom plugins/services Must manage FS, config, output formatting
LSP client CLI Reuse existing LSP server, speak JSON-RPC More setup (start server, send requests)

Building a Custom CLI

1. Shared Language Service Factory

Factor your language service creation into a reusable module (used by LSP + CLI):

export function createVolarService(tsconfigPath: string, config: MyConfig) {
  const tsProject = createTypeScriptProject(tsconfigPath);
  const core = createLanguageCore({ plugins: [...], ts: tsProject.typescript });
  return createLanguageService(core, [volarServiceCss(), customService(config)], env, project);
}

2. CLI Entrypoint

#!/usr/bin/env node
import { URI } from 'vscode-uri';
import glob from 'fast-glob';
import chalk from 'chalk';
import { createVolarService } from './service';

async function main() {
  const service = createVolarService(process.argv[2] ?? 'tsconfig.json', loadConfig());
  const files = await glob(['src/**/*.vue', 'src/**/*.ts']);

  let hasErrors = false;
  for (const file of files) {
    const uri = URI.file(file).toString();
    const diagnostics = await service.getDiagnostics(uri);
    diagnostics.forEach((diag) => {
      hasErrors = hasErrors || diag.severity === 1;
      console.log(formatDiagnostic(file, diag));
    });
  }

  process.exit(hasErrors ? 1 : 0);
}

3. Formatting Output

Use a standard format (VS Code-style) so editors/CI parse easily:

function formatDiagnostic(file: string, diag: Diagnostic) {
  const range = `${diag.range.start.line + 1}:${diag.range.start.character + 1}`;
  const severity = ['Error', 'Warning', 'Information', 'Hint'][diag.severity ?? 0];
  return `${chalk.gray(file)}:${range} - ${severity} ${diag.message} (${diag.source})`;
}

4. JSON Output (Optional)

Provide --json flag to emit machine-readable diagnostics:

if (argv.json) {
  console.log(JSON.stringify({ uri, diagnostics }, null, 2));
}

Leveraging workspace/diagnostic

Instead of looping per file, reuse the workspace diagnostics pipeline:

const report = await service.context.project.context.languageService.getWorkspaceDiagnostics();
report.forEach((docReport) => {
  docReport.items.forEach((diag) => {
    console.log(formatDiagnostic(URI.parse(docReport.uri).fsPath, diag));
  });
});

This ensures CLI output matches editor diagnostics exactly.

Integrating with CI

  1. Add a script (volar-check) that runs your CLI.
  2. Wire it into CI workflows:
- run: npm run volar-check -- --json > artifacts/volar.json
- uses: actions/upload-artifact@v4
  with:
    name: volar-diagnostics
    path: artifacts/volar.json
  1. Fail the pipeline when exit code ≠ 0.

Pre-commit Hooks

Use lint-staged or husky to run targeted diagnostics:

{
  "lint-staged": {
    "*.{vue,ts,js}": "volar-check --files"
  }
}

Implement --files flag to accept a comma-separated list and restrict diagnostics.

Formatting & Code Actions

You can expose formatting or quick fixes via CLI:

const edits = await service.getDocumentFormattingEdits(uri, { tabSize: 2, insertSpaces: true }, undefined);
applyEditsToFile(fsPath, edits);

For code actions, use service.getCodeActions and apply WorkspaceEdit.

Logging & Telemetry

  • Print progress (“Analyzing 123 files…”) with timestamps.
  • Collect metrics (time per file, total diagnostics) to feed into benchmarking dashboards.

Packaging & Distribution

  • Bundle with pkg/nexe if users lack Node.
  • Provide npx entry for quick runs (npx volar-check).
  • Document environment variables (VOLAR_TRACE, VOLAR_CONFIG_PATH) to customize behavior.

Best Practices Checklist

  • Shared service factory reused by both LSP and CLI.
  • Configurable input (tsconfig, glob patterns, file list).
  • Structured output (text + optional JSON).
  • Proper exit codes (0 = success, 1 = errors, 2 = config failure).
  • Support for ignoring warnings (e.g., --max-warnings).
  • Telemetry/logging toggles for verbose debugging.

By bringing Volars language service into CLI form, you align editor diagnostics with automated checks, prevent regressions before they hit production, and empower teams to build custom workflows (codemods, linting, documentation pipelines) on top of the same intelligence.