@@ -2,9 +2,9 @@ import * as vscode from 'vscode';
22import parse from "json-to-ast" ;
33import { pluginSnippets } from "./constants" ;
44import { getASTNode , getRangeFromASTNode } from "./helpers" ;
5- import { DevProxyInstall } from ' ./types' ;
5+ import { DevProxyInstall , PluginConfig } from " ./types" ;
66
7- export const updateConfigDiagnostics = (
7+ export const updateConfigFileDiagnostics = (
88 context : vscode . ExtensionContext ,
99 document : vscode . TextDocument ,
1010 collection : vscode . DiagnosticCollection ,
@@ -14,145 +14,16 @@ export const updateConfigDiagnostics = (
1414 return ;
1515 }
1616 const diagnostics : vscode . Diagnostic [ ] = [ ] ;
17- const documentNode = parse ( document . getText ( ) ) as parse . ObjectNode ;
17+ const documentNode = getObjectNodeFromDocument ( document ) ;
18+ const pluginsNode = getPluginsNode ( documentNode ) ;
1819
19- // check if schema version is compatible
2020 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 ) ;
15122
15223 collection . set ( document . uri , diagnostics ) ;
15324} ;
15425
155- export const updateDiagnostics = (
26+ export const updateFileDiagnostics = (
15627 context : vscode . ExtensionContext ,
15728 document : vscode . TextDocument ,
15829 collection : vscode . DiagnosticCollection ,
@@ -163,15 +34,14 @@ export const updateDiagnostics = (
16334 }
16435
16536 const diagnostics : vscode . Diagnostic [ ] = [ ] ;
166- const documentNode = parse ( document . getText ( ) ) as parse . ObjectNode ;
37+ const documentNode = getObjectNodeFromDocument ( document ) ;
16738
168- // check if schema version is compatible
16939 checkSchemaCompatibility ( documentNode , devProxyInstall , diagnostics ) ;
17040
17141 collection . set ( document . uri , diagnostics ) ;
17242} ;
17343
174- export const checkSchemaCompatibility = ( documentNode : parse . ObjectNode , devProxyInstall : DevProxyInstall , diagnostics : vscode . Diagnostic [ ] ) => {
44+ const checkSchemaCompatibility = ( documentNode : parse . ObjectNode , devProxyInstall : DevProxyInstall , diagnostics : vscode . Diagnostic [ ] ) => {
17545 const schemaNode = getASTNode ( documentNode . children , 'Identifier' , '$schema' ) ;
17646 if ( schemaNode ) {
17747 const schemaValue = ( schemaNode . value as parse . LiteralNode ) . value as string ;
@@ -187,3 +57,182 @@ export const checkSchemaCompatibility = (documentNode: parse.ObjectNode, devProx
18757 }
18858 }
18959} ;
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