11import * as React from "react" ;
2- import * as CompileConfig from "../../../config.json" ;
32
43import Config from "../../config" ;
5- import { AdvancedSkipRuleSet , SkipRuleAttribute , SkipRuleOperator } from "../../utils/skipRule" ;
6- import { ActionType , ActionTypes , CategorySkipOption } from "../../types" ;
4+ import { AdvancedSkipRule , configToText , parseConfig , } from "../../utils/skipRule" ;
75
86let configSaveTimeout : NodeJS . Timeout | null = null ;
97
@@ -64,210 +62,16 @@ export function AdvancedSkipOptionsComponent() {
6462 ) ;
6563}
6664
67- function compileConfig ( config : string ) : AdvancedSkipRuleSet [ ] | null {
68- const ruleSets : AdvancedSkipRuleSet [ ] = [ ] ;
65+ function compileConfig ( config : string ) : AdvancedSkipRule [ ] | null {
66+ const { rules , errors } = parseConfig ( config ) ;
6967
70- let ruleSet : AdvancedSkipRuleSet = {
71- rules : [ ] ,
72- skipOption : null ,
73- comment : ""
74- } ;
75-
76- for ( const line of config . split ( "\n" ) ) {
77- if ( line . trim ( ) . length === 0 ) {
78- // Skip empty lines
79- continue ;
80- }
81-
82- const comment = line . match ( / ^ \s * \/ \/ ( .+ ) $ / ) ;
83- if ( comment ) {
84- if ( ruleSet . rules . length > 0 ) {
85- // Rule has already been created, add it to list if valid
86- if ( ruleSet . skipOption !== null && ruleSet . rules . length > 0 ) {
87- ruleSets . push ( ruleSet ) ;
88-
89- ruleSet = {
90- rules : [ ] ,
91- skipOption : null ,
92- comment : ""
93- } ;
94- } else {
95- return null ;
96- }
97- }
98-
99- if ( ruleSet . comment . length > 0 ) {
100- ruleSet . comment += "; " ;
101- }
102-
103- ruleSet . comment += comment [ 1 ] . trim ( ) ;
104-
105- // Skip comment lines
106- continue ;
107- } else if ( line . startsWith ( "if " ) ) {
108- if ( ruleSet . rules . length > 0 ) {
109- // Rule has already been created, add it to list if valid
110- if ( ruleSet . skipOption !== null && ruleSet . rules . length > 0 ) {
111- ruleSets . push ( ruleSet ) ;
112-
113- ruleSet = {
114- rules : [ ] ,
115- skipOption : null ,
116- comment : ""
117- } ;
118- } else {
119- return null ;
120- }
121- }
122-
123- const ruleTexts = [ ...line . matchAll ( / \S + \S + (?: " [ ^ " \\ ] * (?: \\ .[ ^ " \\ ] * ) * " | \d + ) (? = a n d | $ ) / g) ] ;
124- for ( const ruleText of ruleTexts ) {
125- if ( ! ruleText [ 0 ] ) return null ;
126-
127- const ruleParts = ruleText [ 0 ] . match ( / ( \S + ) ( \S + ) ( " [ ^ " \\ ] * (?: \\ .[ ^ " \\ ] * ) * " | \d + ) / ) ;
128- if ( ruleParts . length !== 4 ) {
129- return null ; // Invalid rule format
130- }
131-
132- const attribute = getSkipRuleAttribute ( ruleParts [ 1 ] ) ;
133- const operator = getSkipRuleOperator ( ruleParts [ 2 ] ) ;
134- const value = getSkipRuleValue ( ruleParts [ 3 ] ) ;
135- if ( attribute === null || operator === null || value === null ) {
136- return null ; // Invalid attribute or operator
137- }
138-
139- if ( [ SkipRuleOperator . Equal , SkipRuleOperator . NotEqual ] . includes ( operator ) ) {
140- if ( attribute === SkipRuleAttribute . Category
141- && ! CompileConfig . categoryList . includes ( value as string ) ) {
142- return null ; // Invalid category value
143- } else if ( attribute === SkipRuleAttribute . ActionType
144- && ! ActionTypes . includes ( value as ActionType ) ) {
145- return null ; // Invalid category value
146- } else if ( attribute === SkipRuleAttribute . Source
147- && ! [ "local" , "youtube" , "autogenerated" , "server" ] . includes ( value as string ) ) {
148- return null ; // Invalid category value
149- }
150- }
151-
152- ruleSet . rules . push ( {
153- attribute,
154- operator,
155- value
156- } ) ;
157- }
158-
159- // Make sure all rules were parsed
160- if ( ruleTexts . length === 0 || ! line . endsWith ( ruleTexts [ ruleTexts . length - 1 ] [ 0 ] ) ) {
161- return null ;
162- }
163- } else {
164- // Only continue if a rule has been defined
165- if ( ruleSet . rules . length === 0 ) {
166- return null ; // No rules defined yet
167- }
168-
169- switch ( line . trim ( ) . toLowerCase ( ) ) {
170- case "disabled" :
171- ruleSet . skipOption = CategorySkipOption . Disabled ;
172- break ;
173- case "show overlay" :
174- ruleSet . skipOption = CategorySkipOption . ShowOverlay ;
175- break ;
176- case "manual skip" :
177- ruleSet . skipOption = CategorySkipOption . ManualSkip ;
178- break ;
179- case "auto skip" :
180- ruleSet . skipOption = CategorySkipOption . AutoSkip ;
181- break ;
182- default :
183- return null ; // Invalid skip option
184- }
185- }
68+ for ( const error of errors ) {
69+ console . error ( `[SB] Error on line ${ error . span . start . line } : ${ error . message } ` ) ;
18670 }
18771
188- if ( ruleSet . rules . length > 0 && ruleSet . skipOption !== null ) {
189- ruleSets . push ( ruleSet ) ;
190- } else if ( ruleSet . rules . length > 0 || ruleSet . skipOption !== null ) {
191- // Incomplete rule set
192- return null ;
193- }
194-
195- return ruleSets ;
196- }
197-
198- function getSkipRuleAttribute ( attribute : string ) : SkipRuleAttribute | null {
199- if ( attribute && Object . values ( SkipRuleAttribute ) . includes ( attribute as SkipRuleAttribute ) ) {
200- return attribute as SkipRuleAttribute ;
201- }
202-
203- return null ;
204- }
205-
206- function getSkipRuleOperator ( operator : string ) : SkipRuleOperator | null {
207- if ( operator && Object . values ( SkipRuleOperator ) . includes ( operator as SkipRuleOperator ) ) {
208- return operator as SkipRuleOperator ;
209- }
210-
211- return null ;
212- }
213-
214- function getSkipRuleValue ( value : string ) : string | number | null {
215- if ( ! value ) return null ;
216-
217- if ( value . startsWith ( '"' ) ) {
218- try {
219- return JSON . parse ( value ) ;
220- } catch ( e ) {
221- return null ; // Invalid JSON string
222- }
72+ if ( errors . length === 0 ) {
73+ return rules ;
22374 } else {
224- const numValue = Number ( value ) ;
225- if ( ! isNaN ( numValue ) ) {
226- return numValue ;
227- }
228-
22975 return null ;
23076 }
23177}
232-
233- function configToText ( config : AdvancedSkipRuleSet [ ] ) : string {
234- let result = "" ;
235-
236- for ( const ruleSet of config ) {
237- if ( ruleSet . comment ) {
238- result += "// " + ruleSet . comment + "\n" ;
239- }
240-
241- result += "if " ;
242- let firstRule = true ;
243- for ( const rule of ruleSet . rules ) {
244- if ( ! firstRule ) {
245- result += " and " ;
246- }
247-
248- result += `${ rule . attribute } ${ rule . operator } ${ JSON . stringify ( rule . value ) } ` ;
249- firstRule = false ;
250- }
251-
252- switch ( ruleSet . skipOption ) {
253- case CategorySkipOption . Disabled :
254- result += "\nDisabled" ;
255- break ;
256- case CategorySkipOption . ShowOverlay :
257- result += "\nShow Overlay" ;
258- break ;
259- case CategorySkipOption . ManualSkip :
260- result += "\nManual Skip" ;
261- break ;
262- case CategorySkipOption . AutoSkip :
263- result += "\nAuto Skip" ;
264- break ;
265- default :
266- return null ; // Invalid skip option
267- }
268-
269- result += "\n\n" ;
270- }
271-
272- return result . trim ( ) ;
273- }
0 commit comments