0
# Language Server
1
2
The Relay Compiler includes a full Language Server Protocol (LSP) implementation that provides IDE integration with real-time GraphQL validation, auto-completion, hover information, and go-to-definition functionality.
3
4
## Starting the Language Server
5
6
```bash
7
{ .api }
8
relay-compiler lsp [OPTIONS]
9
```
10
11
### Options
12
13
```bash
14
{ .api }
15
--config <PATH> # Config file path
16
--output <KIND> # Verbosity level (default: quiet-with-errors)
17
--locate-command <SCRIPT> # Script for GraphQL entity location lookup
18
```
19
20
### Output Levels
21
22
```typescript
23
{ .api }
24
type OutputKind = "debug" | "quiet" | "quiet-with-errors" | "verbose";
25
```
26
27
## Basic Usage
28
29
```bash
30
# Start with default configuration discovery
31
relay-compiler lsp
32
33
# Start with specific configuration
34
relay-compiler lsp --config ./relay.config.json
35
36
# Start with debug output for troubleshooting
37
relay-compiler lsp --output debug
38
39
# Start with custom entity location script
40
relay-compiler lsp --locate-command "./scripts/find-graphql-definition.sh"
41
```
42
43
## IDE Integration
44
45
### VS Code
46
47
The Relay LSP integrates with the official Relay extension for VS Code. The binary resolution logic is shared between the CLI and the extension.
48
49
**Installation:**
50
1. Install the Relay extension from the VS Code marketplace
51
2. Ensure `relay-compiler` is installed in your project
52
3. Configure your `relay.config.json`
53
4. The extension will automatically start the LSP
54
55
### Other IDEs
56
57
Any editor that supports LSP can integrate with the Relay language server:
58
59
- **Vim/Neovim**: Use LSP clients like `nvim-lspconfig` or `vim-lsp`
60
- **Emacs**: Use `lsp-mode` or `eglot`
61
- **Sublime Text**: Use `LSP` package
62
- **IntelliJ/WebStorm**: Built-in LSP support
63
64
## LSP Features
65
66
### Real-time Validation
67
68
The language server provides immediate feedback on GraphQL syntax and semantic errors:
69
70
```typescript
71
{ .api }
72
interface ValidationFeatures {
73
syntaxErrors: boolean; // GraphQL syntax validation
74
schemaValidation: boolean; // Schema conformance checking
75
relaySpecificRules: boolean; // Relay-specific validation rules
76
fragmentValidation: boolean; // Fragment usage validation
77
}
78
```
79
80
### Auto-completion
81
82
Context-aware completions for:
83
84
- Field names from GraphQL schema
85
- Fragment names
86
- Directive names and arguments
87
- Type names
88
- Enum values
89
90
### Hover Information
91
92
Rich hover tooltips showing:
93
94
- Field types and descriptions
95
- Argument types and documentation
96
- Fragment definitions
97
- Schema documentation
98
99
### Go-to-Definition
100
101
Navigate from usage to definition for:
102
103
- Fragment definitions
104
- Schema types and fields
105
- Custom scalar definitions
106
107
### Diagnostics
108
109
Real-time error and warning reporting:
110
111
```typescript
112
{ .api }
113
interface DiagnosticTypes {
114
errors: string[]; // Compilation errors
115
warnings: string[]; // Potential issues
116
deprecations: string[]; // Deprecated field usage
117
suggestions: string[]; // Code improvement suggestions
118
}
119
```
120
121
## Custom Entity Location
122
123
For implementation-first GraphQL schemas, you can provide a custom script to locate GraphQL entity definitions.
124
125
```bash
126
{ .api }
127
--locate-command <SCRIPT>
128
```
129
130
### Script Interface
131
132
The locate command script receives entity information and should return location details:
133
134
```bash
135
# Script input (stdin):
136
# JSON object with entity information
137
{
138
"type": "field" | "type" | "directive",
139
"name": "string",
140
"parent": "string",
141
"schema": "path/to/schema"
142
}
143
144
# Script output (stdout):
145
# JSON object with location information
146
{
147
"file": "path/to/file",
148
"line": 42,
149
"column": 15
150
}
151
```
152
153
### Example Locate Script
154
155
```bash
156
#!/bin/bash
157
# find-graphql-definition.sh
158
159
input=$(cat)
160
entity_type=$(echo "$input" | jq -r '.type')
161
entity_name=$(echo "$input" | jq -r '.name')
162
163
case "$entity_type" in
164
"field")
165
# Search for field definition in resolvers
166
location=$(grep -n "resolve.*$entity_name" src/resolvers/*.js | head -1)
167
;;
168
"type")
169
# Search for type definition
170
location=$(grep -n "type $entity_name" src/schema/*.js | head -1)
171
;;
172
esac
173
174
if [[ -n "$location" ]]; then
175
file=$(echo "$location" | cut -d':' -f1)
176
line=$(echo "$location" | cut -d':' -f2)
177
echo "{\"file\": \"$file\", \"line\": $line, \"column\": 1}"
178
fi
179
```
180
181
## LSP Configuration
182
183
The language server uses the same configuration as the CLI compiler. All configuration options apply to LSP functionality.
184
185
### Project-specific Settings
186
187
```json
188
{
189
"language": "typescript",
190
"src": "./src",
191
"schema": "./schema.graphql",
192
"schemaExtensions": ["./src/schema-extensions"],
193
"featureFlags": {
194
"enable_fragment_argument_transform": "enabled"
195
}
196
}
197
```
198
199
### Multi-project Support
200
201
The LSP automatically detects which project context applies based on the file being edited:
202
203
```json
204
{
205
"sources": {
206
"./apps/web/src": "web",
207
"./apps/mobile/src": "mobile"
208
},
209
"projects": {
210
"web": {
211
"language": "typescript",
212
"schema": "./apps/web/schema.graphql"
213
},
214
"mobile": {
215
"language": "typescript",
216
"schema": "./apps/mobile/schema.graphql"
217
}
218
}
219
}
220
```
221
222
## Schema Documentation Integration
223
224
The LSP can load and display schema documentation from various sources:
225
226
```typescript
227
{ .api }
228
interface SchemaDocumentationLoader {
229
loadFieldDocumentation(typeName: string, fieldName: string): Promise<string>;
230
loadTypeDocumentation(typeName: string): Promise<string>;
231
loadDirectiveDocumentation(directiveName: string): Promise<string>;
232
}
233
```
234
235
### Documentation Sources
236
237
- **SDL Comments**: Standard GraphQL SDL documentation comments
238
- **Custom Loaders**: External documentation systems
239
- **Markdown Files**: Documentation in markdown format
240
241
## Extra Data Provider
242
243
Extend LSP functionality with custom data providers:
244
245
```typescript
246
{ .api }
247
interface LSPExtraDataProvider {
248
getFieldDefinitionSourceInfo(
249
typeName: string,
250
fieldName: string
251
): Promise<FieldDefinitionSourceInfo>;
252
253
getFieldSchemaInfo(
254
typeName: string,
255
fieldName: string
256
): Promise<FieldSchemaInfo>;
257
}
258
259
interface FieldDefinitionSourceInfo {
260
filePath: string;
261
line: number;
262
column: number;
263
}
264
265
interface FieldSchemaInfo {
266
description?: string;
267
deprecationReason?: string;
268
defaultValue?: any;
269
}
270
```
271
272
### Custom Provider Example
273
274
```rust
275
use relay_lsp::{LSPExtraDataProvider, FieldDefinitionSourceInfo, FieldSchemaInfo};
276
277
pub struct CustomDataProvider {
278
schema_registry: SchemaRegistry,
279
}
280
281
impl LSPExtraDataProvider for CustomDataProvider {
282
async fn get_field_definition_source_info(
283
&self,
284
type_name: &str,
285
field_name: &str,
286
) -> Option<FieldDefinitionSourceInfo> {
287
// Custom logic to locate field definitions
288
self.schema_registry.find_field_source(type_name, field_name)
289
}
290
291
async fn get_field_schema_info(
292
&self,
293
type_name: &str,
294
field_name: &str,
295
) -> Option<FieldSchemaInfo> {
296
// Custom logic to provide field information
297
self.schema_registry.get_field_info(type_name, field_name)
298
}
299
}
300
```
301
302
## Error Handling
303
304
The LSP provides comprehensive error handling and reporting:
305
306
```typescript
307
{ .api }
308
interface LSPErrors {
309
ConfigurationError: string; // Invalid configuration
310
SchemaLoadError: string; // Schema loading failures
311
ValidationError: string; // GraphQL validation failures
312
FileSystemError: string; // File access issues
313
LocateCommandError: string; // Custom locate script failures
314
}
315
```
316
317
### Common Error Scenarios
318
319
- **Configuration not found**: LSP will show helpful configuration discovery information
320
- **Schema file missing**: Clear error with path resolution guidance
321
- **Invalid GraphQL syntax**: Real-time syntax error highlighting
322
- **Locate command failures**: Fallback to basic LSP functionality
323
324
## Performance Optimization
325
326
The LSP is optimized for large codebases:
327
328
### Incremental Updates
329
330
- Only reprocesses changed files
331
- Maintains in-memory schema cache
332
- Efficient fragment dependency tracking
333
334
### Memory Management
335
336
- Configurable cache limits
337
- Automatic cleanup of unused data
338
- Efficient string interning
339
340
### Watchman Integration
341
342
```bash
343
{ .api }
344
FORCE_NO_WATCHMAN=1 # Disable Watchman, use filesystem polling
345
```
346
347
When Watchman is available, the LSP uses it for efficient file watching. Otherwise, it falls back to filesystem polling.
348
349
## Troubleshooting
350
351
### Debug Mode
352
353
```bash
354
relay-compiler lsp --output debug
355
```
356
357
Debug mode provides detailed logging for:
358
- Configuration loading
359
- Schema parsing
360
- File watching events
361
- Validation cycles
362
- Custom locate command execution
363
364
### Log Output
365
366
The LSP writes logs to stderr, making it compatible with most LSP clients that capture and display server logs.
367
368
### Common Issues
369
370
1. **LSP not starting**: Check configuration file validity
371
2. **No completions**: Verify schema file accessibility
372
3. **Incorrect go-to-definition**: Configure locate command properly
373
4. **Performance issues**: Enable Watchman or reduce project size