diff --git a/src/persist/helper.ts b/src/persist/helper.ts index 18e5a1d..2ddbb88 100644 --- a/src/persist/helper.ts +++ b/src/persist/helper.ts @@ -1,36 +1,47 @@ import { Model } from '../model'; import { parse } from 'csv-parse/sync'; -export class Helper { - public static loadPolicyLine(line: string, model: Model): void { +export interface IPolicyParser { + parse(line: string): string[][] | null; +} + +export class BasicCsvParser implements IPolicyParser { + parse(line: string): string[][] | null { if (!line || line.trimStart().charAt(0) === '#') { - return; + return null; } - const rawTokens = parse(line, { + return parse(line, { delimiter: ',', skip_empty_lines: true, trim: true, relax_quotes: true, }); + } +} - if (!rawTokens || rawTokens.length === 0 || !rawTokens[0]) { - return; - } +export class BracketAwareCsvParser implements IPolicyParser { + private readonly baseParser: IPolicyParser; - const tokens: string[] = rawTokens[0]; + constructor(baseParser: IPolicyParser = new BasicCsvParser()) { + this.baseParser = baseParser; + } + + parse(line: string): string[][] | null { + const rawTokens = this.baseParser.parse(line); + if (!rawTokens || !rawTokens[0]) { + return null; + } + const tokens = rawTokens[0]; const processedTokens: string[] = []; let currentToken = ''; let bracketCount = 0; for (const token of tokens) { for (const char of token) { - if (char === '(') { - bracketCount++; - } else if (char === ')') { - bracketCount--; - } + if (char === '(') bracketCount++; + else if (char === ')') bracketCount--; } currentToken += (currentToken ? ',' : '') + token; @@ -45,11 +56,24 @@ export class Helper { throw new Error(`Unmatched brackets in policy line: ${line}`); } - if (processedTokens.length === 0) { + return processedTokens.length > 0 ? [processedTokens] : null; + } +} + +export class PolicyLoader { + private readonly parser: IPolicyParser; + + constructor(parser: IPolicyParser = new BracketAwareCsvParser()) { + this.parser = parser; + } + + loadPolicyLine(line: string, model: Model): void { + const tokens = this.parser.parse(line); + if (!tokens || !tokens[0]) { return; } - let key = processedTokens[0].trim(); + let key = tokens[0][0].trim(); if (key.startsWith('"') && key.endsWith('"')) { key = key.slice(1, -1); } @@ -65,7 +89,7 @@ export class Helper { return; } - const values = processedTokens.slice(1).map((v) => { + const values = tokens[0].slice(1).map((v) => { if (v.startsWith('"') && v.endsWith('"')) { v = v.slice(1, -1); } @@ -75,3 +99,11 @@ export class Helper { policy.policy.push(values); } } + +export class Helper { + private static readonly policyLoader = new PolicyLoader(); + + public static loadPolicyLine(line: string, model: Model): void { + Helper.policyLoader.loadPolicyLine(line, model); + } +}