0
# Syntax Highlighting
1
2
The syntax highlighting domain provides code syntax highlighting capabilities for Prisma schemas, SQL, and TypeScript/JavaScript code, enabling rich console output and improved developer experience.
3
4
## Functions
5
6
### Prisma Schema Highlighting
7
8
#### `highlightDatamodel(str)`
9
10
Applies syntax highlighting to Prisma datamodel (schema) strings with color codes for different language elements.
11
12
```typescript { .api }
13
function highlightDatamodel(str: string): any
14
```
15
16
**Parameters:**
17
- `str: string` - Prisma datamodel string to highlight
18
19
**Returns:** `any` - String with ANSI color codes for syntax highlighting
20
21
**Highlighted Elements:**
22
- **Keywords:** `model`, `enum`, `type`, `generator`, `datasource`
23
- **Field Types:** `String`, `Int`, `Boolean`, `DateTime`, `Json`, etc.
24
- **Attributes:** `@id`, `@unique`, `@default`, `@@map`, etc.
25
- **Relations:** `@relation`
26
- **Comments:** `//` and `/* */` comments
27
- **Strings:** Quoted string values
28
- **Numbers:** Numeric literals
29
30
**Example:**
31
```typescript
32
import { highlightDatamodel } from '@prisma/internals'
33
34
const schema = `
35
model User {
36
id Int @id @default(autoincrement())
37
email String @unique
38
name String?
39
posts Post[]
40
createdAt DateTime @default(now())
41
42
@@map("users")
43
}
44
45
model Post {
46
id Int @id @default(autoincrement())
47
title String
48
content String?
49
authorId Int
50
author User @relation(fields: [authorId], references: [id])
51
}
52
`
53
54
const highlighted = highlightDatamodel(schema)
55
console.log(highlighted)
56
// Output will include color codes:
57
// - Blue for keywords (model, String, Int, etc.)
58
// - Green for attributes (@id, @unique, etc.)
59
// - Yellow for strings
60
// - Gray for comments
61
```
62
63
### SQL Highlighting
64
65
#### `highlightSql(str)`
66
67
Applies syntax highlighting to SQL query strings with appropriate color coding for SQL elements.
68
69
```typescript { .api }
70
function highlightSql(str: string): any
71
```
72
73
**Parameters:**
74
- `str: string` - SQL string to highlight
75
76
**Returns:** `any` - String with ANSI color codes for SQL syntax highlighting
77
78
**Highlighted Elements:**
79
- **Keywords:** `SELECT`, `FROM`, `WHERE`, `JOIN`, `INSERT`, `UPDATE`, `DELETE`
80
- **Functions:** `COUNT`, `SUM`, `AVG`, `MAX`, `MIN`, etc.
81
- **Operators:** `=`, `<>`, `>`, `<`, `AND`, `OR`, `NOT`
82
- **Strings:** Single-quoted string literals
83
- **Numbers:** Numeric literals
84
- **Comments:** `--` and `/* */` comments
85
- **Identifiers:** Table and column names
86
87
**Example:**
88
```typescript
89
import { highlightSql } from '@prisma/internals'
90
91
const sqlQuery = `
92
SELECT
93
u.id,
94
u.email,
95
u.name,
96
COUNT(p.id) as post_count
97
FROM users u
98
LEFT JOIN posts p ON u.id = p.author_id
99
WHERE u.created_at > '2024-01-01'
100
AND u.email LIKE '%@example.com'
101
GROUP BY u.id, u.email, u.name
102
ORDER BY post_count DESC
103
LIMIT 10;
104
`
105
106
const highlighted = highlightSql(sqlQuery)
107
console.log(highlighted)
108
// Output will include color codes:
109
// - Blue for SQL keywords (SELECT, FROM, WHERE, etc.)
110
// - Green for functions (COUNT, etc.)
111
// - Yellow for string literals
112
// - Cyan for table/column identifiers
113
```
114
115
### TypeScript/JavaScript Highlighting
116
117
#### `highlightTS(str)`
118
119
Applies syntax highlighting to TypeScript/JavaScript code strings with color coding for language constructs.
120
121
```typescript { .api }
122
function highlightTS(str: string): any
123
```
124
125
**Parameters:**
126
- `str: string` - TypeScript/JavaScript string to highlight
127
128
**Returns:** `any` - String with ANSI color codes for TypeScript/JavaScript syntax highlighting
129
130
**Highlighted Elements:**
131
- **Keywords:** `function`, `const`, `let`, `var`, `if`, `else`, `for`, `while`, `class`, `interface`, `type`
132
- **Types:** `string`, `number`, `boolean`, `object`, `any`, `void`, `undefined`
133
- **Operators:** `=`, `===`, `!==`, `=>`, `&&`, `||`, `!`
134
- **Strings:** Single and double-quoted strings, template literals
135
- **Numbers:** Numeric literals
136
- **Comments:** `//` and `/* */` comments
137
- **Built-ins:** `console`, `Promise`, `Array`, etc.
138
139
**Example:**
140
```typescript
141
import { highlightTS } from '@prisma/internals'
142
143
const code = `
144
interface User {
145
id: number;
146
email: string;
147
name?: string;
148
posts: Post[];
149
}
150
151
async function createUser(data: Omit<User, 'id'>): Promise<User> {
152
const user = await prisma.user.create({
153
data: {
154
email: data.email,
155
name: data.name || 'Anonymous'
156
},
157
include: {
158
posts: true
159
}
160
});
161
162
console.log(\`Created user: \${user.email}\`);
163
return user;
164
}
165
166
const newUser = await createUser({
167
email: 'john@example.com',
168
name: 'John Doe',
169
posts: []
170
});
171
`
172
173
const highlighted = highlightTS(code)
174
console.log(highlighted)
175
// Output will include color codes:
176
// - Purple for keywords (interface, async, function, etc.)
177
// - Blue for types (number, string, Promise, etc.)
178
// - Green for strings and template literals
179
// - Yellow for function names
180
// - Cyan for object properties
181
```
182
183
## Examples
184
185
### Code Documentation Generator
186
187
```typescript
188
import {
189
highlightDatamodel,
190
highlightSql,
191
highlightTS
192
} from '@prisma/internals'
193
194
interface CodeBlock {
195
language: 'prisma' | 'sql' | 'typescript' | 'javascript'
196
code: string
197
title?: string
198
description?: string
199
}
200
201
class DocumentationGenerator {
202
203
/**
204
* Generate highlighted code block for documentation
205
*/
206
generateCodeBlock(block: CodeBlock): string {
207
const { language, code, title, description } = block
208
209
let highlighted: string
210
211
// Apply appropriate highlighting based on language
212
switch (language) {
213
case 'prisma':
214
highlighted = highlightDatamodel(code)
215
break
216
case 'sql':
217
highlighted = highlightSql(code)
218
break
219
case 'typescript':
220
case 'javascript':
221
highlighted = highlightTS(code)
222
break
223
default:
224
highlighted = code // No highlighting for unknown languages
225
}
226
227
// Build formatted output
228
let output = ''
229
230
if (title) {
231
output += `\nπ ${title}\n`
232
output += '='.repeat(title.length + 3) + '\n'
233
}
234
235
if (description) {
236
output += `${description}\n\n`
237
}
238
239
output += `Language: ${language.toUpperCase()}\n`
240
output += '-'.repeat(40) + '\n'
241
output += highlighted
242
output += '\n' + '-'.repeat(40) + '\n'
243
244
return output
245
}
246
247
/**
248
* Generate documentation for multiple code blocks
249
*/
250
generateDocumentation(blocks: CodeBlock[]): string {
251
return blocks
252
.map(block => this.generateCodeBlock(block))
253
.join('\n\n')
254
}
255
}
256
257
// Usage example
258
const docGen = new DocumentationGenerator()
259
260
const codeBlocks: CodeBlock[] = [
261
{
262
language: 'prisma',
263
title: 'User Model Definition',
264
description: 'Defines the User model with relations to posts',
265
code: `
266
model User {
267
id Int @id @default(autoincrement())
268
email String @unique
269
name String?
270
posts Post[]
271
profile Profile?
272
createdAt DateTime @default(now())
273
updatedAt DateTime @updatedAt
274
275
@@map("users")
276
}
277
`.trim()
278
},
279
{
280
language: 'sql',
281
title: 'User Analytics Query',
282
description: 'Retrieves user statistics with post counts',
283
code: `
284
SELECT
285
u.id,
286
u.email,
287
u.name,
288
COUNT(p.id) as total_posts,
289
MAX(p.created_at) as last_post_date
290
FROM users u
291
LEFT JOIN posts p ON u.id = p.author_id
292
GROUP BY u.id, u.email, u.name
293
HAVING COUNT(p.id) > 0
294
ORDER BY total_posts DESC;
295
`.trim()
296
},
297
{
298
language: 'typescript',
299
title: 'User Service Implementation',
300
description: 'TypeScript service for user operations',
301
code: `
302
class UserService {
303
constructor(private prisma: PrismaClient) {}
304
305
async createUser(data: CreateUserData): Promise<User> {
306
const user = await this.prisma.user.create({
307
data: {
308
email: data.email,
309
name: data.name,
310
profile: data.profile ? {
311
create: data.profile
312
} : undefined
313
},
314
include: {
315
profile: true,
316
posts: true
317
}
318
});
319
320
return user;
321
}
322
323
async getUserStats(userId: number): Promise<UserStats> {
324
const user = await this.prisma.user.findUnique({
325
where: { id: userId },
326
include: {
327
_count: {
328
select: { posts: true }
329
}
330
}
331
});
332
333
if (!user) {
334
throw new Error('User not found');
335
}
336
337
return {
338
id: user.id,
339
email: user.email,
340
postCount: user._count.posts
341
};
342
}
343
}
344
`.trim()
345
}
346
]
347
348
const documentation = docGen.generateDocumentation(codeBlocks)
349
console.log(documentation)
350
```
351
352
### Interactive Code Viewer
353
354
```typescript
355
import {
356
highlightDatamodel,
357
highlightSql,
358
highlightTS
359
} from '@prisma/internals'
360
361
interface ViewerOptions {
362
showLineNumbers?: boolean
363
wrapLongLines?: boolean
364
colorScheme?: 'dark' | 'light'
365
}
366
367
class InteractiveCodeViewer {
368
private options: ViewerOptions
369
370
constructor(options: ViewerOptions = {}) {
371
this.options = {
372
showLineNumbers: true,
373
wrapLongLines: true,
374
colorScheme: 'dark',
375
...options
376
}
377
}
378
379
/**
380
* Display code with syntax highlighting and optional line numbers
381
*/
382
displayCode(
383
code: string,
384
language: 'prisma' | 'sql' | 'typescript',
385
title?: string
386
): void {
387
// Apply syntax highlighting
388
let highlighted: string
389
switch (language) {
390
case 'prisma':
391
highlighted = highlightDatamodel(code)
392
break
393
case 'sql':
394
highlighted = highlightSql(code)
395
break
396
case 'typescript':
397
highlighted = highlightTS(code)
398
break
399
}
400
401
// Split into lines for processing
402
const lines = highlighted.split('\n')
403
404
// Display header
405
if (title) {
406
console.log(`\nπ ${title}`)
407
console.log('β'.repeat(process.stdout.columns || 80))
408
}
409
410
// Display code with optional line numbers
411
lines.forEach((line, index) => {
412
let output = ''
413
414
if (this.options.showLineNumbers) {
415
const lineNum = (index + 1).toString().padStart(3, ' ')
416
output += `${lineNum} β `
417
}
418
419
output += line
420
421
// Handle long lines
422
if (this.options.wrapLongLines && output.length > (process.stdout.columns || 80)) {
423
// Simple wrapping - could be enhanced
424
console.log(output.substring(0, process.stdout.columns || 80))
425
console.log(' β ' + output.substring(process.stdout.columns || 80))
426
} else {
427
console.log(output)
428
}
429
})
430
431
console.log('β'.repeat(process.stdout.columns || 80))
432
console.log(`Language: ${language.toUpperCase()} | Lines: ${lines.length}`)
433
}
434
435
/**
436
* Compare two code blocks side by side
437
*/
438
compareCode(
439
leftCode: string,
440
rightCode: string,
441
leftLanguage: 'prisma' | 'sql' | 'typescript',
442
rightLanguage: 'prisma' | 'sql' | 'typescript',
443
leftTitle = 'Before',
444
rightTitle = 'After'
445
): void {
446
const leftHighlighted = this.highlightByLanguage(leftCode, leftLanguage)
447
const rightHighlighted = this.highlightByLanguage(rightCode, rightLanguage)
448
449
const leftLines = leftHighlighted.split('\n')
450
const rightLines = rightHighlighted.split('\n')
451
const maxLines = Math.max(leftLines.length, rightLines.length)
452
const halfWidth = Math.floor((process.stdout.columns || 80) / 2) - 2
453
454
console.log(`\n${leftTitle.padEnd(halfWidth)} β ${rightTitle}`)
455
console.log('β'.repeat(halfWidth) + 'βΌ' + 'β'.repeat(halfWidth))
456
457
for (let i = 0; i < maxLines; i++) {
458
const leftLine = (leftLines[i] || '').substring(0, halfWidth).padEnd(halfWidth)
459
const rightLine = (rightLines[i] || '').substring(0, halfWidth)
460
461
console.log(`${leftLine} β ${rightLine}`)
462
}
463
464
console.log('β'.repeat(halfWidth) + 'β΄' + 'β'.repeat(halfWidth))
465
}
466
467
private highlightByLanguage(
468
code: string,
469
language: 'prisma' | 'sql' | 'typescript'
470
): string {
471
switch (language) {
472
case 'prisma':
473
return highlightDatamodel(code)
474
case 'sql':
475
return highlightSql(code)
476
case 'typescript':
477
return highlightTS(code)
478
default:
479
return code
480
}
481
}
482
}
483
484
// Usage
485
const viewer = new InteractiveCodeViewer({
486
showLineNumbers: true,
487
wrapLongLines: true,
488
colorScheme: 'dark'
489
})
490
491
// Display Prisma schema
492
viewer.displayCode(`
493
model User {
494
id Int @id @default(autoincrement())
495
email String @unique
496
posts Post[]
497
}
498
499
model Post {
500
id Int @id @default(autoincrement())
501
title String
502
authorId Int
503
author User @relation(fields: [authorId], references: [id])
504
}
505
`, 'prisma', 'Database Schema')
506
507
// Compare SQL queries
508
viewer.compareCode(
509
`SELECT * FROM users WHERE active = true`,
510
`SELECT id, email, name FROM users WHERE active = true AND verified = true`,
511
'sql',
512
'sql',
513
'Original Query',
514
'Optimized Query'
515
)
516
```
517
518
### Code Quality Reporter
519
520
```typescript
521
import {
522
highlightDatamodel,
523
highlightSql,
524
highlightTS
525
} from '@prisma/internals'
526
527
interface CodeIssue {
528
line: number
529
column: number
530
severity: 'error' | 'warning' | 'info'
531
message: string
532
rule?: string
533
}
534
535
interface AnalysisResult {
536
code: string
537
language: 'prisma' | 'sql' | 'typescript'
538
issues: CodeIssue[]
539
score: number
540
}
541
542
class CodeQualityReporter {
543
544
/**
545
* Generate quality report with highlighted code and issues
546
*/
547
generateReport(result: AnalysisResult): void {
548
const { code, language, issues, score } = result
549
550
console.log('\nπ Code Quality Report')
551
console.log('β'.repeat(50))
552
553
// Overall score
554
const scoreColor = score >= 80 ? 'π’' : score >= 60 ? 'π‘' : 'π΄'
555
console.log(`${scoreColor} Quality Score: ${score}/100`)
556
console.log(`π Language: ${language.toUpperCase()}`)
557
console.log(`β οΈ Issues Found: ${issues.length}`)
558
console.log()
559
560
// Issue summary
561
const errors = issues.filter(i => i.severity === 'error').length
562
const warnings = issues.filter(i => i.severity === 'warning').length
563
const infos = issues.filter(i => i.severity === 'info').length
564
565
if (issues.length > 0) {
566
console.log('π Issue Summary:')
567
if (errors > 0) console.log(` π΄ Errors: ${errors}`)
568
if (warnings > 0) console.log(` π‘ Warnings: ${warnings}`)
569
if (infos > 0) console.log(` π΅ Info: ${infos}`)
570
console.log()
571
}
572
573
// Highlighted code with issue markers
574
console.log('π Code with Issues:')
575
console.log('β'.repeat(50))
576
577
let highlighted: string
578
switch (language) {
579
case 'prisma':
580
highlighted = highlightDatamodel(code)
581
break
582
case 'sql':
583
highlighted = highlightSql(code)
584
break
585
case 'typescript':
586
highlighted = highlightTS(code)
587
break
588
}
589
590
const lines = highlighted.split('\n')
591
592
lines.forEach((line, index) => {
593
const lineNumber = index + 1
594
const lineIssues = issues.filter(issue => issue.line === lineNumber)
595
596
// Display line with number
597
const lineNumStr = lineNumber.toString().padStart(3, ' ')
598
let prefix = ' '
599
600
if (lineIssues.length > 0) {
601
const maxSeverity = lineIssues.reduce((max, issue) => {
602
if (issue.severity === 'error') return 'error'
603
if (max === 'error') return max
604
if (issue.severity === 'warning') return 'warning'
605
return issue.severity
606
}, 'info' as const)
607
608
switch (maxSeverity) {
609
case 'error':
610
prefix = 'π΄ '
611
break
612
case 'warning':
613
prefix = 'π‘ '
614
break
615
case 'info':
616
prefix = 'π΅ '
617
break
618
}
619
}
620
621
console.log(`${prefix}${lineNumStr} β ${line}`)
622
623
// Display issues for this line
624
lineIssues.forEach(issue => {
625
const indent = ' '.repeat(7 + issue.column)
626
const marker = '^'.repeat(Math.min(issue.message.length, 20))
627
console.log(`${indent}${marker}`)
628
629
const severityIcon = {
630
error: 'π΄',
631
warning: 'π‘',
632
info: 'π΅'
633
}[issue.severity]
634
635
console.log(`${indent}${severityIcon} ${issue.message}`)
636
if (issue.rule) {
637
console.log(`${indent} Rule: ${issue.rule}`)
638
}
639
})
640
})
641
642
console.log('β'.repeat(50))
643
644
// Recommendations
645
if (issues.length > 0) {
646
console.log('\nπ‘ Recommendations:')
647
const uniqueRules = [...new Set(issues.map(i => i.rule).filter(Boolean))]
648
uniqueRules.forEach(rule => {
649
console.log(` β’ Review rule: ${rule}`)
650
})
651
652
if (errors > 0) {
653
console.log(' β’ Fix all errors before deployment')
654
}
655
if (warnings > 5) {
656
console.log(' β’ Consider addressing warnings to improve code quality')
657
}
658
} else {
659
console.log('\nβ No issues found - great job!')
660
}
661
}
662
}
663
664
// Usage
665
const reporter = new CodeQualityReporter()
666
667
const analysisResult: AnalysisResult = {
668
code: `
669
model User {
670
id Int @id @default(autoincrement())
671
email String @unique
672
password String // Should be hashed
673
posts Post[]
674
}
675
676
model Post {
677
id Int @id @default(autoincrement())
678
title String
679
authorId Int
680
author User @relation(fields: [authorId], references: [id])
681
}
682
`.trim(),
683
language: 'prisma',
684
issues: [
685
{
686
line: 4,
687
column: 12,
688
severity: 'warning',
689
message: 'Password field should include @db.Text for longer hashes',
690
rule: 'password-field-type'
691
},
692
{
693
line: 11,
694
column: 3,
695
severity: 'info',
696
message: 'Consider adding cascade delete behavior',
697
rule: 'relation-delete-behavior'
698
}
699
],
700
score: 85
701
}
702
703
reporter.generateReport(analysisResult)
704
```