1
+ /**
2
+ * It should be noted that the existence of this script is far from ideal.
3
+ * The goal here is to prevent any new TypeScript errors from being committed
4
+ * to the code base, while giving the PageBuilder team the opportunity
5
+ * to incrementally address existing compiler errors.
6
+ *
7
+ * A snapshot (in `ts-errors.json`) has been taken of all compiler errors
8
+ * (and their respective metadata) to be checked against prior to any new
9
+ * merges.
10
+ *
11
+ * Whenever this whole project passes a run of `tsc` without errors,
12
+ * this script should be removed, and the CI process for PageBuilder
13
+ * should be updated to fail the build on *any* TypeScript error.
14
+ */
15
+
16
+ const chalk = require ( 'chalk' ) ;
17
+ const stripANSI = require ( 'strip-ansi' ) ;
18
+ const priorStats = require ( './ts-errors.json' ) ;
19
+
20
+ let chunks = [ ] ;
21
+
22
+ process . stdin . on ( 'readable' , ( ) => {
23
+ const chunk = process . stdin . read ( ) ;
24
+ if ( chunk !== null ) chunks . push ( chunk ) ;
25
+ } ) ;
26
+
27
+ process . stdin . on ( 'end' , ( ) => {
28
+ // strip coloring and other decorations
29
+ const tsOutput = stripANSI ( chunks . join ( '' ) ) . trim ( ) ;
30
+ // each unique error is delimited by two line breaks
31
+ const lines = tsOutput . split ( '\n\n' ) ;
32
+ const compilerErrors = { } ;
33
+
34
+ while ( lines . length ) {
35
+ const [ rawError , rawSnippet ] = lines . splice ( 0 , 2 ) ;
36
+ const [
37
+ ,
38
+ file ,
39
+ line ,
40
+ column ,
41
+ errorCode ,
42
+ message
43
+ ] = rawError . match ( / ( .+ ) \( ( \d + ) , ( \d + ) \) : e r r o r ( T S \d + ) : ( .+ ) / ) ;
44
+
45
+ const fileErrors = compilerErrors [ file ] = compilerErrors [ file ] || [ ] ;
46
+
47
+ fileErrors . push ( {
48
+ file,
49
+ line,
50
+ column,
51
+ errorCode,
52
+ message,
53
+ rawError,
54
+ rawSnippet
55
+ } ) ;
56
+ }
57
+
58
+ const newErrors = [ ] ;
59
+ // Walk each file to do an error comparison
60
+ for ( const [ file , errors ] of Object . entries ( compilerErrors ) ) {
61
+ let newErrs = errors ;
62
+ // Walk each file to do an error comparison
63
+ const oldFileErrors = priorStats [ file ] ;
64
+ if ( oldFileErrors && oldFileErrors . length > 0 ) {
65
+ // Walk over all the tsc-reported errors in this file
66
+ newErrs = errors . filter ( e => {
67
+ // Check if the error from this current iteration matches a previous
68
+ // error from the states file on disk
69
+ return ! oldFileErrors . some ( err => err . message === e . message ) ;
70
+ } ) ;
71
+ }
72
+ // Collect any newly-reported errors
73
+ newErrors . push ( ...newErrs ) ;
74
+ }
75
+
76
+ if ( ! newErrors . length ) {
77
+ process . exit ( 0 ) ;
78
+ }
79
+
80
+ console . log (
81
+ chalk . red ( `${ newErrors . length } new TypeScript errors were introduced to the code base with your changes. \n` ) +
82
+ chalk . white . bgRed ( 'You' , chalk . white . bgRed ( 'must' ) , 'resolve all new TypeScript errors before merging a PR.' )
83
+ ) ;
84
+
85
+ newErrors . forEach ( err => {
86
+ console . log ( chalk . red ( err . rawError + "\n" ) ) ;
87
+ err . rawSnippet . split ( "\n" ) . forEach ( raw => {
88
+ console . log ( " " + raw ) ;
89
+ } ) ;
90
+ } ) ;
91
+
92
+ console . log (
93
+ "\n" +
94
+ chalk . red ( `${ newErrors . length } new TypeScript errors were introduced to the code base with your changes. \n` ) +
95
+ chalk . white . bgRed ( 'You' , chalk . white . bgRed ( 'must' ) , 'resolve all new TypeScript errors before merging a PR.' )
96
+ ) ;
97
+ } ) ;
0 commit comments