1
+ // `yaml` is not type safe 🤷♂️
2
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3
+ /* eslint-disable @typescript-eslint/no-explicit-any */
4
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
1
5
import { Injectable , InternalServerErrorException } from '@nestjs/common' ;
2
6
import child_process from 'child_process' ;
3
7
import fs from 'fs' ;
4
8
import * as uuid from 'uuid' ;
9
+ import YAML from 'yaml' ;
5
10
import { ConvertToGolangCILintOutput } from './linters/golangcilint' ;
6
11
import { ConvertToPylintOutput } from './linters/pylint' ;
7
12
@@ -26,7 +31,24 @@ export class LintService {
26
31
output = output . substring ( 0 , output . length - 1 ) ;
27
32
const pylintOutput = ConvertToPylintOutput . toPylintOutput ( output ) ;
28
33
if ( pylintOutput ) {
29
- // Remove one point to the score per violation
34
+ /*
35
+ Example output:
36
+ [
37
+ {
38
+ "type": "convention",
39
+ "module": "fib",
40
+ "obj": "",
41
+ "line": 1,
42
+ "column": 0,
43
+ "path": "fib.py",
44
+ "symbol": "missing-module-docstring",
45
+ "message": "Missing module docstring",
46
+ "message-id": "C0114"
47
+ },
48
+ ...
49
+
50
+ Remove one point to the score per violation
51
+ */
30
52
return 100 - pylintOutput . length ;
31
53
}
32
54
} catch ( e ) {
@@ -63,6 +85,31 @@ export class LintService {
63
85
const lintOuput =
64
86
ConvertToGolangCILintOutput . toGolangCILintOutput ( output ) ;
65
87
if ( lintOuput ) {
88
+ /*
89
+ Example output:
90
+
91
+ {
92
+ "Issues": [
93
+ {
94
+ "FromLinter": "errcheck",
95
+ "Text": "Error return value of `http.ListenAndServe` is not checked",
96
+ "Severity": "",
97
+ "SourceLines": [
98
+ "\thttp.ListenAndServe(\":9567\", nil)"
99
+ ],
100
+ "Replacement": null,
101
+ "Pos": {
102
+ "Filename": "http.go",
103
+ "Offset": 417,
104
+ "Line": 27,
105
+ "Column": 21
106
+ },
107
+ "ExpectNoLint": false,
108
+ "ExpectedNoLintLinter": ""
109
+ }
110
+ ],
111
+ ...
112
+ */
66
113
if ( lintOuput . issues ) {
67
114
// Remove one point to the score per violation
68
115
return 100 - lintOuput . issues . length ;
@@ -76,4 +123,56 @@ export class LintService {
76
123
77
124
throw new InternalServerErrorException ( ) ;
78
125
}
126
+
127
+ lintCpp ( code : string ) : number {
128
+ // clang-tidy doesn't support stdin
129
+ const path = `/tmp/codebench_${ uuid . v4 ( ) } .cpp` ;
130
+ const outputPath = `${ path } .yaml` ;
131
+ try {
132
+ fs . writeFileSync ( path , code ) ;
133
+ } catch ( e ) {
134
+ throw new InternalServerErrorException ( e ) ;
135
+ }
136
+
137
+ const result = child_process . spawnSync ( 'clang-tidy' , [
138
+ `-export-fixes=${ outputPath } ` ,
139
+ path ,
140
+ '--' ,
141
+ '-Wall' ,
142
+ '-std=c++11' ,
143
+ '-x' ,
144
+ 'c++' ,
145
+ ] ) ;
146
+
147
+ if ( result . error ) {
148
+ throw new InternalServerErrorException ( result . error ) ;
149
+ }
150
+
151
+ try {
152
+ if ( fs . existsSync ( outputPath ) ) {
153
+ const file = fs . readFileSync ( `${ path } .yaml` , 'utf8' ) ;
154
+ const fixes : any = YAML . parse ( file ) ;
155
+ if ( fixes ) {
156
+ /*
157
+ Example file:
158
+ ---
159
+ MainSourceFile: /root/fib.cpp
160
+ Diagnostics:
161
+ - DiagnosticName: clang-diagnostic-unused-variable
162
+ Message: 'unused variable ''d'''
163
+ FileOffset: 142
164
+ FilePath: /root/fib.cpp
165
+ Replacements:
166
+ ...
167
+ */
168
+ if ( fixes . Diagnostics ) {
169
+ return 100 - fixes . Diagnostics . length ;
170
+ }
171
+ }
172
+ }
173
+ return 100 ;
174
+ } catch ( e ) {
175
+ throw new InternalServerErrorException ( e ) ;
176
+ }
177
+ }
79
178
}
0 commit comments