1
1
import { Model } from '../model' ;
2
2
import { parse } from 'csv-parse/sync' ;
3
3
4
- export class Helper {
5
- public static loadPolicyLine ( line : string , model : Model ) : void {
4
+ export interface IPolicyParser {
5
+ parse ( line : string ) : string [ ] [ ] | null ;
6
+ }
7
+
8
+ export class BasicCsvParser implements IPolicyParser {
9
+ parse ( line : string ) : string [ ] [ ] | null {
6
10
if ( ! line || line . trimStart ( ) . charAt ( 0 ) === '#' ) {
7
- return ;
11
+ return null ;
8
12
}
9
13
10
- const tokens = parse ( line , {
14
+ return parse ( line , {
11
15
delimiter : ',' ,
12
16
skip_empty_lines : true ,
13
17
trim : true ,
18
+ relax_quotes : true ,
14
19
} ) ;
20
+ }
21
+ }
22
+
23
+ export class BracketAwareCsvParser implements IPolicyParser {
24
+ private readonly baseParser : IPolicyParser ;
25
+
26
+ constructor ( baseParser : IPolicyParser = new BasicCsvParser ( ) ) {
27
+ this . baseParser = baseParser ;
28
+ }
29
+
30
+ parse ( line : string ) : string [ ] [ ] | null {
31
+ const rawTokens = this . baseParser . parse ( line ) ;
32
+ if ( ! rawTokens || ! rawTokens [ 0 ] ) {
33
+ return null ;
34
+ }
35
+
36
+ const tokens = rawTokens [ 0 ] ;
37
+ const processedTokens : string [ ] = [ ] ;
38
+ let currentToken = '' ;
39
+ let bracketCount = 0 ;
40
+
41
+ for ( const token of tokens ) {
42
+ for ( const char of token ) {
43
+ if ( char === '(' ) bracketCount ++ ;
44
+ else if ( char === ')' ) bracketCount -- ;
45
+ }
46
+
47
+ currentToken += ( currentToken ? ',' : '' ) + token ;
48
+
49
+ if ( bracketCount === 0 ) {
50
+ processedTokens . push ( currentToken ) ;
51
+ currentToken = '' ;
52
+ }
53
+ }
54
+
55
+ if ( bracketCount !== 0 ) {
56
+ throw new Error ( `Unmatched brackets in policy line: ${ line } ` ) ;
57
+ }
58
+
59
+ return processedTokens . length > 0 ? [ processedTokens ] : null ;
60
+ }
61
+ }
62
+
63
+ export class PolicyLoader {
64
+ private readonly parser : IPolicyParser ;
15
65
66
+ constructor ( parser : IPolicyParser = new BracketAwareCsvParser ( ) ) {
67
+ this . parser = parser ;
68
+ }
69
+
70
+ loadPolicyLine ( line : string , model : Model ) : void {
71
+ const tokens = this . parser . parse ( line ) ;
16
72
if ( ! tokens || ! tokens [ 0 ] ) {
17
73
return ;
18
74
}
19
75
20
- const key = tokens [ 0 ] [ 0 ] ;
76
+ let key = tokens [ 0 ] [ 0 ] . trim ( ) ;
77
+ if ( key . startsWith ( '"' ) && key . endsWith ( '"' ) ) {
78
+ key = key . slice ( 1 , - 1 ) ;
79
+ }
80
+
21
81
const sec = key . substring ( 0 , 1 ) ;
22
82
const item = model . model . get ( sec ) ;
23
83
if ( ! item ) {
@@ -28,6 +88,22 @@ export class Helper {
28
88
if ( ! policy ) {
29
89
return ;
30
90
}
31
- policy . policy . push ( tokens [ 0 ] . slice ( 1 ) ) ;
91
+
92
+ const values = tokens [ 0 ] . slice ( 1 ) . map ( ( v ) => {
93
+ if ( v . startsWith ( '"' ) && v . endsWith ( '"' ) ) {
94
+ v = v . slice ( 1 , - 1 ) ;
95
+ }
96
+ return v . replace ( / " " / g, '"' ) . trim ( ) ;
97
+ } ) ;
98
+
99
+ policy . policy . push ( values ) ;
100
+ }
101
+ }
102
+
103
+ export class Helper {
104
+ private static readonly policyLoader = new PolicyLoader ( ) ;
105
+
106
+ public static loadPolicyLine ( line : string , model : Model ) : void {
107
+ Helper . policyLoader . loadPolicyLine ( line , model ) ;
32
108
}
33
109
}
0 commit comments