Skip to content

Commit

Permalink
feat: add support for regexp
Browse files Browse the repository at this point in the history
  • Loading branch information
koladilip committed May 25, 2024
1 parent 312cad1 commit f864b2f
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 5 deletions.
62 changes: 59 additions & 3 deletions src/lexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,12 @@ export class JsonTemplateLexer {
};
}

const token = this.scanPunctuator() ?? this.scanID() ?? this.scanString() ?? this.scanInteger();
const token =
this.scanRegularExpressions() ??
this.scanPunctuator() ??
this.scanID() ??
this.scanString() ??
this.scanInteger();
if (token) {
return token;
}
Expand Down Expand Up @@ -314,7 +319,8 @@ export class JsonTemplateLexer {
token.type === TokenType.FLOAT ||
token.type === TokenType.STR ||
token.type === TokenType.NULL ||
token.type === TokenType.UNDEFINED
token.type === TokenType.UNDEFINED ||
token.type === TokenType.REGEXP
);
}

Expand Down Expand Up @@ -541,7 +547,7 @@ export class JsonTemplateLexer {
};
}
} else if (ch1 === '=') {
if ('^$*'.indexOf(ch2) >= 0) {
if ('^$*~'.indexOf(ch2) >= 0) {
this.idx += 2;
return {
type: TokenType.PUNCT,
Expand Down Expand Up @@ -638,6 +644,56 @@ export class JsonTemplateLexer {
}
}

private static isValidRegExp(regexp: string, modifiers: string) {
try {
RegExp(regexp, modifiers);
return true;
} catch (e) {
return false;
}
}

private getRegExpModifiers(): string {
let modifiers = '';
while ('gimsuyv'.includes(this.codeChars[this.idx])) {
modifiers += this.codeChars[this.idx];
this.idx++;
}
return modifiers;
}

private scanRegularExpressions(): Token | undefined {
const start = this.idx;
const ch1 = this.codeChars[this.idx];

if (ch1 === '/') {
let end = this.idx + 1;
while (end < this.codeChars.length) {
if (this.codeChars[end] === '\n') {
return;
}
if (this.codeChars[end] === '/') {
break;
}
end++;
}

if (end < this.codeChars.length) {
this.idx = end + 1;
const regexp = this.getCode(start + 1, end);
const modifiers = this.getRegExpModifiers();
if (!JsonTemplateLexer.isValidRegExp(regexp, modifiers)) {
JsonTemplateLexer.throwError("invalid regular expression '%0'", regexp);
}
return {
type: TokenType.REGEXP,
value: this.getCode(start, this.idx),
range: [start, this.idx],
};
}
}
}

private scanPunctuator(): Token | undefined {
return (
this.scanPunctuatorForDots() ??
Expand Down
3 changes: 3 additions & 0 deletions src/operators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export const binaryOperators = {

'=$': (val1, val2): string => endsWith(val2, val1),

'=~': (val1, val2): string =>
`(${val2} instanceof RegExp) ? (${val2}.test(${val1})) : (${val1}==${val2})`,

contains: containsStrict,

'==*': (val1, val2): string => containsStrict(val2, val1),
Expand Down
2 changes: 1 addition & 1 deletion src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,7 @@ export class JsonTemplateParser {
this.lexer.match('$=') ||
this.lexer.match('=$') ||
this.lexer.match('==*') ||
this.lexer.match('=~') ||
this.lexer.match('=*')
) {
return {
Expand All @@ -690,7 +691,6 @@ export class JsonTemplateParser {
args: [expr, this.parseEqualityExpr()],
};
}

return expr;
}

Expand Down
3 changes: 3 additions & 0 deletions src/translator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,9 @@ export class JsonTemplateTranslator {
if (type === TokenType.STR) {
return escapeStr(val);
}
if (type === TokenType.REGEXP) {
return val;
}
return String(val);
}

Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export enum TokenType {
THROW = 'throw',
KEYWORD = 'keyword',
EOT = 'eot',
REGEXP = 'regexp',
}

// In the order of precedence
Expand Down
1 change: 1 addition & 0 deletions test/scenarios/bad_templates/bad_regex.jt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/?/
4 changes: 4 additions & 0 deletions test/scenarios/bad_templates/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export const data: Scenario[] = [
templatePath: 'bad_number.jt',
error: 'Unexpected token',
},
{
templatePath: 'bad_regex.jt',
error: 'invalid regular expression',
},
{
templatePath: 'bad_string.jt',
error: 'Unexpected end of template',
Expand Down
2 changes: 2 additions & 0 deletions test/scenarios/comparisons/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export const data: Scenario[] = [
true,
true,
true,
true,
true,
],
},
];
4 changes: 3 additions & 1 deletion test/scenarios/comparisons/template.jt
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@
"" empty true,
"abc" empty false,
["c", "a"] subsetof ["a", "b", "c"],
[] subsetof ["a", "b", "c"]
[] subsetof ["a", "b", "c"],
"abc" =~ /a.*c/,
"AdC" =~ /a.*c/i,
]

0 comments on commit f864b2f

Please sign in to comment.