@@ -2,9 +2,9 @@ import * as vscode from 'vscode';
2
2
import parse from "json-to-ast" ;
3
3
import { pluginSnippets } from "./constants" ;
4
4
import { getASTNode , getRangeFromASTNode } from "./helpers" ;
5
- import { DevProxyInstall } from ' ./types' ;
5
+ import { DevProxyInstall , PluginConfig } from " ./types" ;
6
6
7
- export const updateConfigDiagnostics = (
7
+ export const updateConfigFileDiagnostics = (
8
8
context : vscode . ExtensionContext ,
9
9
document : vscode . TextDocument ,
10
10
collection : vscode . DiagnosticCollection ,
@@ -14,145 +14,16 @@ export const updateConfigDiagnostics = (
14
14
return ;
15
15
}
16
16
const diagnostics : vscode . Diagnostic [ ] = [ ] ;
17
- const documentNode = parse ( document . getText ( ) ) as parse . ObjectNode ;
17
+ const documentNode = getObjectNodeFromDocument ( document ) ;
18
+ const pluginsNode = getPluginsNode ( documentNode ) ;
18
19
19
- // check if schema version is compatible
20
20
checkSchemaCompatibility ( documentNode , devProxyInstall , diagnostics ) ;
21
-
22
- // check validity of plugins
23
- const pluginsNode = getASTNode (
24
- documentNode . children ,
25
- 'Identifier' ,
26
- 'plugins'
27
- ) ;
28
- if (
29
- pluginsNode &&
30
- ( pluginsNode . value as parse . ArrayNode ) . children . length !== 0
31
- ) {
32
- const pluginNodes = ( pluginsNode . value as parse . ArrayNode )
33
- . children as parse . ObjectNode [ ] ;
34
-
35
- // check for plugins
36
- if ( pluginNodes . length === 0 ) {
37
- diagnostics . push (
38
- new vscode . Diagnostic (
39
- getRangeFromASTNode ( pluginsNode ) ,
40
- 'Add at least one plugin' ,
41
- vscode . DiagnosticSeverity . Error
42
- )
43
- ) ;
44
- }
45
-
46
- // check if we have any plugins that contain the name reporter in the plugins node
47
- const reporterIndex = pluginNodes . findIndex ( ( pluginNode : parse . ObjectNode ) => {
48
- const pluginNameNode = getASTNode (
49
- pluginNode . children ,
50
- 'Identifier' ,
51
- 'name'
52
- ) ;
53
- const pluginName = ( pluginNameNode ?. value as parse . LiteralNode )
54
- . value as string ;
55
- return pluginName . toLowerCase ( ) . includes ( 'reporter' ) ;
56
- } ) ;
57
-
58
- if ( reporterIndex !== - 1 ) {
59
- // check if we have any more plugins after the reporter plugin
60
- const pluginsAfterReporter = pluginNodes . slice ( reporterIndex + 1 ) ;
61
- // if we do, add a warning to the reporter plugin stating that it should be the last plugin
62
- if ( pluginsAfterReporter . length > 0 ) {
63
- // check if there are any plugins after the reporter plugin that are not reporters
64
- const pluginAfterReporter = pluginsAfterReporter . find ( ( pluginNode : parse . ObjectNode ) => {
65
- const pluginNameNode = getASTNode (
66
- pluginNode . children ,
67
- 'Identifier' ,
68
- 'name'
69
- ) ;
70
- const pluginName = ( pluginNameNode ?. value as parse . LiteralNode )
71
- . value as string ;
72
- return ! pluginName . toLowerCase ( ) . includes ( 'reporter' ) ;
73
- } ) ;
74
- // if there are, add a warning to the reporter plugin
75
- if ( pluginAfterReporter ) {
76
- const diagnostic = new vscode . Diagnostic (
77
- getRangeFromASTNode ( pluginNodes [ reporterIndex ] ) ,
78
- 'Reporters should be placed after other plugins.' ,
79
- vscode . DiagnosticSeverity . Warning
80
- ) ;
81
- diagnostics . push ( diagnostic ) ;
82
- }
83
- }
84
- }
85
-
86
- // does the plugin have a config section?
87
- pluginNodes . forEach ( ( pluginNode : parse . ObjectNode ) => {
88
- const pluginNameNode = getASTNode (
89
- pluginNode . children ,
90
- 'Identifier' ,
91
- 'name'
92
- ) ;
93
- const pluginName = ( pluginNameNode ?. value as parse . LiteralNode )
94
- . value as string ;
95
- const enabledNode = getASTNode (
96
- pluginNode . children ,
97
- 'Identifier' ,
98
- 'enabled'
99
- ) ;
100
- const isEnabled = ( enabledNode ?. value as parse . LiteralNode )
101
- . value as boolean ;
102
- const pluginSnippet = pluginSnippets [ pluginName ] ;
103
- const requiresConfig = pluginSnippet . config
104
- ? pluginSnippet . config . required
105
- : false ;
106
-
107
- if ( requiresConfig ) {
108
- // check to see if the plugin has a config section
109
- const configSectionNode = getASTNode (
110
- pluginNode . children ,
111
- 'Identifier' ,
112
- 'configSection'
113
- ) ;
114
- if ( ! configSectionNode ) {
115
- // there is no config section defined on the plugin instance
116
- diagnostics . push (
117
- new vscode . Diagnostic (
118
- getRangeFromASTNode ( pluginNode ) ,
119
- `${ pluginName } requires a config section.` ,
120
- isEnabled
121
- ? vscode . DiagnosticSeverity . Error
122
- : vscode . DiagnosticSeverity . Warning
123
- )
124
- ) ;
125
- } else {
126
- // check to see if the config section is in the document
127
- const configSectionName = (
128
- configSectionNode . value as parse . LiteralNode
129
- ) . value as string ;
130
- const configSection = getASTNode (
131
- documentNode . children ,
132
- 'Identifier' ,
133
- configSectionName
134
- ) ;
135
-
136
- if ( ! configSection ) {
137
- diagnostics . push (
138
- new vscode . Diagnostic (
139
- getRangeFromASTNode ( configSectionNode . value ) ,
140
- `${ configSectionName } config section is missing. Use '${ pluginSnippet . config ?. name } ' snippet to create one.` ,
141
- isEnabled
142
- ? vscode . DiagnosticSeverity . Error
143
- : vscode . DiagnosticSeverity . Warning
144
- )
145
- ) ;
146
- }
147
- }
148
- }
149
- } ) ;
150
- }
21
+ checkPlugins ( pluginsNode , diagnostics , documentNode ) ;
151
22
152
23
collection . set ( document . uri , diagnostics ) ;
153
24
} ;
154
25
155
- export const updateDiagnostics = (
26
+ export const updateFileDiagnostics = (
156
27
context : vscode . ExtensionContext ,
157
28
document : vscode . TextDocument ,
158
29
collection : vscode . DiagnosticCollection ,
@@ -163,15 +34,14 @@ export const updateDiagnostics = (
163
34
}
164
35
165
36
const diagnostics : vscode . Diagnostic [ ] = [ ] ;
166
- const documentNode = parse ( document . getText ( ) ) as parse . ObjectNode ;
37
+ const documentNode = getObjectNodeFromDocument ( document ) ;
167
38
168
- // check if schema version is compatible
169
39
checkSchemaCompatibility ( documentNode , devProxyInstall , diagnostics ) ;
170
40
171
41
collection . set ( document . uri , diagnostics ) ;
172
42
} ;
173
43
174
- export const checkSchemaCompatibility = ( documentNode : parse . ObjectNode , devProxyInstall : DevProxyInstall , diagnostics : vscode . Diagnostic [ ] ) => {
44
+ const checkSchemaCompatibility = ( documentNode : parse . ObjectNode , devProxyInstall : DevProxyInstall , diagnostics : vscode . Diagnostic [ ] ) => {
175
45
const schemaNode = getASTNode ( documentNode . children , 'Identifier' , '$schema' ) ;
176
46
if ( schemaNode ) {
177
47
const schemaValue = ( schemaNode . value as parse . LiteralNode ) . value as string ;
@@ -187,3 +57,182 @@ export const checkSchemaCompatibility = (documentNode: parse.ObjectNode, devProx
187
57
}
188
58
}
189
59
} ;
60
+
61
+ const checkPlugins = ( pluginsNode : parse . PropertyNode | undefined , diagnostics : vscode . Diagnostic [ ] , documentNode : parse . ObjectNode ) => {
62
+ if ( pluginsNode &&
63
+ ( pluginsNode . value as parse . ArrayNode ) ) {
64
+ const pluginNodes = ( pluginsNode . value as parse . ArrayNode )
65
+ . children as parse . ObjectNode [ ] ;
66
+
67
+ checkAtLeastOneEnabledPlugin ( pluginNodes , diagnostics , pluginsNode ) ;
68
+ warnOnReporterPosition ( pluginNodes , diagnostics ) ;
69
+ validatePluginConfigurations ( pluginNodes , diagnostics , documentNode ) ;
70
+ }
71
+ } ;
72
+
73
+ const validatePluginConfigurations = ( pluginNodes : parse . ObjectNode [ ] , diagnostics : vscode . Diagnostic [ ] , documentNode : parse . ObjectNode ) => {
74
+ pluginNodes . forEach ( ( pluginNode : parse . ObjectNode ) => {
75
+ const pluginNameNode = getASTNode (
76
+ pluginNode . children ,
77
+ 'Identifier' ,
78
+ 'name'
79
+ ) ;
80
+ const pluginName = ( pluginNameNode ?. value as parse . LiteralNode )
81
+ . value as string ;
82
+ const enabledNode = getASTNode (
83
+ pluginNode . children ,
84
+ 'Identifier' ,
85
+ 'enabled'
86
+ ) ;
87
+ const isEnabled = ( enabledNode ?. value as parse . LiteralNode )
88
+ . value as boolean ;
89
+ const pluginSnippet = pluginSnippets [ pluginName ] ;
90
+
91
+ checkPluginConfiguration ( pluginNode , diagnostics , pluginName , isEnabled , documentNode , pluginSnippet ) ;
92
+ } ) ;
93
+ } ;
94
+
95
+ const warnOnReporterPosition = ( pluginNodes : parse . ObjectNode [ ] , diagnostics : vscode . Diagnostic [ ] ) => {
96
+ const reporterIndex = pluginNodes . findIndex ( ( pluginNode : parse . ObjectNode ) => {
97
+ const pluginNameNode = getASTNode (
98
+ pluginNode . children ,
99
+ 'Identifier' ,
100
+ 'name'
101
+ ) ;
102
+ const pluginName = ( pluginNameNode ?. value as parse . LiteralNode )
103
+ . value as string ;
104
+ return pluginName . toLowerCase ( ) . includes ( 'reporter' ) ;
105
+ } ) ;
106
+
107
+ if ( reporterIndex !== - 1 ) {
108
+ // check if we have any more plugins after the reporter plugin
109
+ const pluginsAfterReporter = pluginNodes . slice ( reporterIndex + 1 ) ;
110
+ // if we do, add a warning to the reporter plugin stating that it should be the last plugin
111
+ if ( pluginsAfterReporter . length > 0 ) {
112
+ // check if there are any plugins after the reporter plugin that are not reporters
113
+ const pluginAfterReporter = pluginsAfterReporter . find ( ( pluginNode : parse . ObjectNode ) => {
114
+ const pluginNameNode = getASTNode (
115
+ pluginNode . children ,
116
+ 'Identifier' ,
117
+ 'name'
118
+ ) ;
119
+ const pluginName = ( pluginNameNode ?. value as parse . LiteralNode )
120
+ . value as string ;
121
+ return ! pluginName . toLowerCase ( ) . includes ( 'reporter' ) ;
122
+ } ) ;
123
+ // if there are, add a warning to the reporter plugin
124
+ if ( pluginAfterReporter ) {
125
+ const diagnostic = new vscode . Diagnostic (
126
+ getRangeFromASTNode ( pluginNodes [ reporterIndex ] ) ,
127
+ 'Reporters should be placed after other plugins.' ,
128
+ vscode . DiagnosticSeverity . Warning
129
+ ) ;
130
+ diagnostics . push ( diagnostic ) ;
131
+ }
132
+ }
133
+ }
134
+ } ;
135
+
136
+ const checkAtLeastOneEnabledPlugin = ( pluginNodes : parse . ObjectNode [ ] , diagnostics : vscode . Diagnostic [ ] , pluginsNode : parse . PropertyNode ) => {
137
+ // check if there are any plugins
138
+ if ( pluginNodes . length === 0 ) {
139
+ diagnostics . push (
140
+ new vscode . Diagnostic (
141
+ getRangeFromASTNode ( pluginsNode ) ,
142
+ 'Add at least one plugin' ,
143
+ vscode . DiagnosticSeverity . Error
144
+ )
145
+ ) ;
146
+ } else {
147
+ // check if there are any enabled plugins
148
+ const enabledPlugins = pluginNodes . filter ( ( pluginNode : parse . ObjectNode ) => {
149
+ const enabledNode = getASTNode (
150
+ pluginNode . children ,
151
+ 'Identifier' ,
152
+ 'enabled'
153
+ ) ;
154
+ return ( enabledNode ?. value as parse . LiteralNode ) . value as boolean ;
155
+ } ) ;
156
+ if ( enabledPlugins . length === 0 ) {
157
+ diagnostics . push (
158
+ new vscode . Diagnostic (
159
+ getRangeFromASTNode ( pluginsNode ) ,
160
+ 'At least one plugin must be enabled' ,
161
+ vscode . DiagnosticSeverity . Error
162
+ )
163
+ ) ;
164
+ }
165
+ }
166
+ } ;
167
+
168
+ const checkPluginConfiguration = ( pluginNode : parse . ObjectNode , diagnostics : vscode . Diagnostic [ ] , pluginName : string , isEnabled : boolean , documentNode : parse . ObjectNode , pluginSnippet : { instance : string ; config ?: PluginConfig ; } ) => {
169
+ const configSectionNode = getASTNode (
170
+ pluginNode . children ,
171
+ 'Identifier' ,
172
+ 'configSection'
173
+ ) ;
174
+
175
+ // if the plugin does not require a config section, we should not have one
176
+ if ( ! pluginSnippet . config && configSectionNode ) {
177
+ diagnostics . push (
178
+ new vscode . Diagnostic (
179
+ getRangeFromASTNode ( configSectionNode ) ,
180
+ `${ pluginName } does not require a config section.` ,
181
+ isEnabled
182
+ ? vscode . DiagnosticSeverity . Error
183
+ : vscode . DiagnosticSeverity . Warning
184
+ )
185
+ ) ;
186
+ return ;
187
+ }
188
+
189
+ // if there is no config section defined on the plugin, we should have one if the plugin requires it
190
+ if ( ! configSectionNode ) {
191
+ if ( pluginSnippet . config ?. required ) {
192
+ diagnostics . push (
193
+ new vscode . Diagnostic (
194
+ getRangeFromASTNode ( pluginNode ) ,
195
+ `${ pluginName } requires a config section.` ,
196
+ isEnabled
197
+ ? vscode . DiagnosticSeverity . Error
198
+ : vscode . DiagnosticSeverity . Warning
199
+ )
200
+ ) ;
201
+ }
202
+ } else {
203
+ // if there is a config section defined on the plugin, we should have the config section defined in the document
204
+ const configSectionName = (
205
+ configSectionNode . value as parse . LiteralNode
206
+ ) . value as string ;
207
+ const configSection = getASTNode (
208
+ documentNode . children ,
209
+ 'Identifier' ,
210
+ configSectionName
211
+ ) ;
212
+
213
+ if ( ! configSection ) {
214
+ diagnostics . push (
215
+ new vscode . Diagnostic (
216
+ getRangeFromASTNode ( configSectionNode . value ) ,
217
+ `${ configSectionName } config section is missing. Use '${ pluginSnippet . config ?. name } ' snippet to create one.` ,
218
+ isEnabled
219
+ ? vscode . DiagnosticSeverity . Error
220
+ : vscode . DiagnosticSeverity . Warning
221
+ )
222
+ ) ;
223
+ }
224
+ }
225
+ } ;
226
+
227
+ const getPluginsNode = ( documentNode : parse . ObjectNode ) => {
228
+ return getASTNode (
229
+ documentNode . children ,
230
+ 'Identifier' ,
231
+ 'plugins'
232
+ ) ;
233
+ } ;
234
+
235
+ const getObjectNodeFromDocument = ( document : vscode . TextDocument ) : parse . ObjectNode => {
236
+ return parse ( document . getText ( ) ) as parse . ObjectNode ;
237
+ } ;
238
+
0 commit comments