Skip to content

Commit

Permalink
Update AGTree quote utils and library exports
Browse files Browse the repository at this point in the history
Merge in ADGUARD-FILTERS/tsurlfilter from feature/AG-22383-3 to master

Squashed commit of the following:

commit aea9cda
Merge: ec14da8 e91c717
Author: scripthunter7 <d.tota@adguard.com>
Date:   Thu Aug 10 11:06:31 2023 +0200

    Merge branch 'master' into feature/AG-22383-3

commit ec14da8
Author: scripthunter7 <d.tota@adguard.com>
Date:   Thu Aug 10 10:49:16 2023 +0200

    Update AGTree exports

commit 5340ddd
Author: scripthunter7 <d.tota@adguard.com>
Date:   Thu Aug 10 10:39:07 2023 +0200

    Add quote removal

commit ec0f8b9
Author: scripthunter7 <d.tota@adguard.com>
Date:   Thu Aug 10 10:35:27 2023 +0200

    Change quote utils to class
  • Loading branch information
scripthunter7 committed Aug 10, 2023
1 parent e91c717 commit 8419fd3
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 105 deletions.
7 changes: 5 additions & 2 deletions packages/agtree/src/ast-utils/scriptlets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import cloneDeep from 'clone-deep';

import { type ParameterList } from '../parser/common';
import { type QuoteType, setStringQuoteType } from '../utils/quotes';
import { type QuoteType, QuoteUtils } from '../utils/quotes';

/**
* Get name of the scriptlet from the scriptlet node
Expand Down Expand Up @@ -56,7 +56,10 @@ export function setScriptletQuoteType(scriptletNode: ParameterList, quoteType: Q
const scriptletNodeClone = cloneDeep(scriptletNode);

for (let i = 0; i < scriptletNodeClone.children.length; i += 1) {
scriptletNodeClone.children[i].value = setStringQuoteType(scriptletNodeClone.children[i].value, quoteType);
scriptletNodeClone.children[i].value = QuoteUtils.setStringQuoteType(
scriptletNodeClone.children[i].value,
quoteType,
);
}

return scriptletNodeClone;
Expand Down
4 changes: 2 additions & 2 deletions packages/agtree/src/converter/cosmetic/scriptlets/adg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import cloneDeep from 'clone-deep';

import { QuoteType, setStringQuoteType } from '../../../utils/quotes';
import { QuoteType, QuoteUtils } from '../../../utils/quotes';
import { getScriptletName, setScriptletName, setScriptletQuoteType } from '../../../ast-utils/scriptlets';
import { type ParameterList } from '../../../parser/common';
import { type ConverterFunction } from '../../base-interfaces/converter-function';
Expand All @@ -29,7 +29,7 @@ export class AdgScriptletConverter {
*/
private static convertToAdg(scriptletNode: ParameterList, prefix: Prefix): ParameterList {
// Remove possible quotes just to make it easier to work with the scriptlet name
const scriptletName = setStringQuoteType(
const scriptletName = QuoteUtils.setStringQuoteType(
getScriptletName(scriptletNode),
QuoteType.None,
);
Expand Down
16 changes: 16 additions & 0 deletions packages/agtree/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ export { MetadataCommentRuleParser } from './parser/comment/metadata';
export { ModifierListParser } from './parser/misc/modifier-list';
export { ModifierParser } from './parser/misc/modifier';
export { NetworkRuleParser } from './parser/network';
export { NotImplementedError } from './errors/not-implemented-error';
export { ParameterListParser } from './parser/misc/parameter-list';
export { PreProcessorCommentRuleParser } from './parser/comment/preprocessor';
export { RuleConversionError } from './errors/rule-conversion-error';

// Validator
export { modifierValidator } from './validator';
Expand Down Expand Up @@ -105,6 +107,20 @@ export { CssTreeNodeType, CssTreeParserContext } from './utils/csstree-constants
export { DomainUtils } from './utils/domain';
export { type VariableTable, LogicalExpressionUtils } from './utils/logical-expression';
export { shiftLoc, locRange } from './utils/location';
export {
ADBLOCK_URL_START,
ADBLOCK_URL_START_REGEX,
ADBLOCK_URL_SEPARATOR,
ADBLOCK_URL_SEPARATOR_REGEX,
ADBLOCK_WILDCARD,
ADBLOCK_WILDCARD_REGEX,
SPECIAL_REGEX_SYMBOLS,
RegExpUtils,
} from './utils/regexp';
export {
QuoteType,
QuoteUtils,
} from './utils/quotes';

// Constants
export { METADATA_HEADERS } from './converter/data/metadata';
Expand Down
211 changes: 121 additions & 90 deletions packages/agtree/src/utils/quotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,119 +30,150 @@ export enum QuoteType {
}

/**
* Escape all unescaped occurrences of the character
*
* @param string String to escape
* @param char Character to escape
* @returns Escaped string
* Utility functions for working with quotes
*/
export function escapeUnescapedOccurrences(string: string, char: string): string {
let result = EMPTY;
export class QuoteUtils {
/**
* Escape all unescaped occurrences of the character
*
* @param string String to escape
* @param char Character to escape
* @returns Escaped string
*/
public static escapeUnescapedOccurrences(string: string, char: string): string {
let result = EMPTY;

for (let i = 0; i < string.length; i += 1) {
if (string[i] === char && (i === 0 || string[i - 1] !== ESCAPE_CHARACTER)) {
result += ESCAPE_CHARACTER;
}

for (let i = 0; i < string.length; i += 1) {
if (string[i] === char && (i === 0 || string[i - 1] !== ESCAPE_CHARACTER)) {
result += ESCAPE_CHARACTER;
result += string[i];
}

result += string[i];
return result;
}

return result;
}

/**
* Unescape all single escaped occurrences of the character
*
* @param string String to unescape
* @param char Character to unescape
* @returns Unescaped string
*/
export function unescapeSingleEscapedOccurrences(string: string, char: string): string {
let result = EMPTY;
/**
* Unescape all single escaped occurrences of the character
*
* @param string String to unescape
* @param char Character to unescape
* @returns Unescaped string
*/
public static unescapeSingleEscapedOccurrences(string: string, char: string): string {
let result = EMPTY;

for (let i = 0; i < string.length; i += 1) {
if (
string[i] === char
for (let i = 0; i < string.length; i += 1) {
if (
string[i] === char
&& string[i - 1] === ESCAPE_CHARACTER
&& (i === 1 || string[i - 2] !== ESCAPE_CHARACTER)
) {
result = result.slice(0, -1);
}

result += string[i];
}

return result;
}
) {
result = result.slice(0, -1);
}

/**
* Get quote type of the string
*
* @param string String to check
* @returns Quote type of the string
*/
export function getStringQuoteType(string: string): QuoteType {
// Don't check 1-character strings to avoid false positives
if (string.length > 1) {
if (string.startsWith(SINGLE_QUOTE) && string.endsWith(SINGLE_QUOTE)) {
return QuoteType.Single;
result += string[i];
}

if (string.startsWith(DOUBLE_QUOTE) && string.endsWith(DOUBLE_QUOTE)) {
return QuoteType.Double;
}
return result;
}

return QuoteType.None;
}

/**
* Set quote type of the string
*
* @param string String to set quote type of
* @param quoteType Quote type to set
* @returns String with the specified quote type
*/
export function setStringQuoteType(string: string, quoteType: QuoteType): string {
const actualQuoteType = getStringQuoteType(string);

switch (quoteType) {
case QuoteType.None:
if (actualQuoteType === QuoteType.Single) {
return escapeUnescapedOccurrences(string.slice(1, -1), SINGLE_QUOTE);
/**
* Get quote type of the string
*
* @param string String to check
* @returns Quote type of the string
*/
public static getStringQuoteType(string: string): QuoteType {
// Don't check 1-character strings to avoid false positives
if (string.length > 1) {
if (string.startsWith(SINGLE_QUOTE) && string.endsWith(SINGLE_QUOTE)) {
return QuoteType.Single;
}

if (actualQuoteType === QuoteType.Double) {
return escapeUnescapedOccurrences(string.slice(1, -1), DOUBLE_QUOTE);
if (string.startsWith(DOUBLE_QUOTE) && string.endsWith(DOUBLE_QUOTE)) {
return QuoteType.Double;
}
}

return string;

case QuoteType.Single:
if (actualQuoteType === QuoteType.None) {
return SINGLE_QUOTE + escapeUnescapedOccurrences(string, SINGLE_QUOTE) + SINGLE_QUOTE;
}
return QuoteType.None;
}

if (actualQuoteType === QuoteType.Double) {
/**
* Set quote type of the string
*
* @param string String to set quote type of
* @param quoteType Quote type to set
* @returns String with the specified quote type
*/
public static setStringQuoteType(string: string, quoteType: QuoteType): string {
const actualQuoteType = QuoteUtils.getStringQuoteType(string);

switch (quoteType) {
case QuoteType.None:
if (actualQuoteType === QuoteType.Single) {
return QuoteUtils.escapeUnescapedOccurrences(string.slice(1, -1), SINGLE_QUOTE);
}

if (actualQuoteType === QuoteType.Double) {
return QuoteUtils.escapeUnescapedOccurrences(string.slice(1, -1), DOUBLE_QUOTE);
}

return string;

case QuoteType.Single:
if (actualQuoteType === QuoteType.None) {
return SINGLE_QUOTE + QuoteUtils.escapeUnescapedOccurrences(string, SINGLE_QUOTE) + SINGLE_QUOTE;
}

if (actualQuoteType === QuoteType.Double) {
return SINGLE_QUOTE
+ QuoteUtils.escapeUnescapedOccurrences(
QuoteUtils.unescapeSingleEscapedOccurrences(string.slice(1, -1), DOUBLE_QUOTE),
SINGLE_QUOTE,
) + SINGLE_QUOTE;
}

return string;

case QuoteType.Double:
if (actualQuoteType === QuoteType.None) {
return DOUBLE_QUOTE + QuoteUtils.escapeUnescapedOccurrences(string, DOUBLE_QUOTE) + DOUBLE_QUOTE;
}

if (actualQuoteType !== QuoteType.Double) {
// eslint-disable-next-line max-len
return SINGLE_QUOTE + escapeUnescapedOccurrences(unescapeSingleEscapedOccurrences(string.slice(1, -1), DOUBLE_QUOTE), SINGLE_QUOTE) + SINGLE_QUOTE;
}
return DOUBLE_QUOTE
+ QuoteUtils.escapeUnescapedOccurrences(
QuoteUtils.unescapeSingleEscapedOccurrences(string.slice(1, -1), SINGLE_QUOTE),
DOUBLE_QUOTE,
) + DOUBLE_QUOTE;
}

return string;
return string;

case QuoteType.Double:
if (actualQuoteType === QuoteType.None) {
return DOUBLE_QUOTE + escapeUnescapedOccurrences(string, DOUBLE_QUOTE) + DOUBLE_QUOTE;
}

if (actualQuoteType !== QuoteType.Double) {
// eslint-disable-next-line max-len
return DOUBLE_QUOTE + escapeUnescapedOccurrences(unescapeSingleEscapedOccurrences(string.slice(1, -1), SINGLE_QUOTE), DOUBLE_QUOTE) + DOUBLE_QUOTE;
}
default:
return string;
}
}

return string;
/**
* Removes bounding quotes from a string, if any
*
* @param string Input string
* @returns String without quotes
*/
public static removeQuotes(string: string): string {
if (
// We should check for string length to avoid false positives
string.length > 1
&& (string[0] === SINGLE_QUOTE || string[0] === DOUBLE_QUOTE)
&& string[0] === string[string.length - 1]
) {
return string.slice(1, -1);
}

default:
return string;
return string;
}
}
Loading

0 comments on commit 8419fd3

Please sign in to comment.