@malloydata/malloy-filter 0.0.237-dev250224215546 → 0.0.237-dev250225015031
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SAMPLES.md +336 -114
- package/SERIALIZE_SAMPLES.md +268 -64
- package/dist/a_simple_parser.js +6 -0
- package/dist/a_simple_parser.js.map +1 -1
- package/dist/base_parser.js +6 -0
- package/dist/base_parser.js.map +1 -1
- package/dist/boolean_parser.js +28 -13
- package/dist/boolean_parser.js.map +1 -1
- package/dist/boolean_serializer.js +12 -6
- package/dist/boolean_serializer.js.map +1 -1
- package/dist/clause_types.d.ts +20 -15
- package/dist/clause_types.js +6 -0
- package/dist/clause_types.js.map +1 -1
- package/dist/date_parser.js +135 -116
- package/dist/date_parser.js.map +1 -1
- package/dist/date_serializer.js +26 -20
- package/dist/date_serializer.js.map +1 -1
- package/dist/date_types.d.ts +21 -21
- package/dist/date_types.js +6 -0
- package/dist/date_types.js.map +1 -1
- package/dist/generate_samples.js +32 -25
- package/dist/generate_samples.js.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/number_parser.js +43 -25
- package/dist/number_parser.js.map +1 -1
- package/dist/number_serializer.js +10 -4
- package/dist/number_serializer.js.map +1 -1
- package/dist/string_parser.d.ts +0 -1
- package/dist/string_parser.js +47 -79
- package/dist/string_parser.js.map +1 -1
- package/dist/string_serializer.d.ts +1 -0
- package/dist/string_serializer.js +49 -33
- package/dist/string_serializer.js.map +1 -1
- package/dist/token_types.js +6 -0
- package/dist/token_types.js.map +1 -1
- package/dist/tokenizer.js +9 -3
- package/dist/tokenizer.js.map +1 -1
- package/dist/tokenizer.spec.js +13 -7
- package/dist/tokenizer.spec.js.map +1 -1
- package/package.json +1 -1
- package/src/a_simple_parser.ts +7 -0
- package/src/base_parser.ts +7 -0
- package/src/boolean_parser.ts +30 -18
- package/src/boolean_serializer.ts +13 -6
- package/src/clause_types.ts +36 -31
- package/src/date_parser.ts +136 -118
- package/src/date_serializer.ts +27 -20
- package/src/date_types.ts +42 -34
- package/src/generate_samples.ts +33 -25
- package/src/index.ts +7 -0
- package/src/number_parser.ts +45 -26
- package/src/number_serializer.ts +11 -4
- package/src/string_parser.ts +51 -79
- package/src/string_serializer.ts +65 -39
- package/src/token_types.ts +7 -0
- package/src/tokenizer.spec.ts +14 -7
- package/src/tokenizer.ts +10 -3
package/src/string_parser.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
1
8
|
import {SpecialToken, Tokenizer, TokenizerParams} from './tokenizer';
|
|
2
9
|
import {
|
|
3
10
|
StringClause,
|
|
4
11
|
StringCondition,
|
|
12
|
+
StringMatchOperator,
|
|
5
13
|
StringConditionOperator,
|
|
6
|
-
|
|
7
|
-
FilterError,
|
|
14
|
+
FilterLog,
|
|
8
15
|
StringParserResponse,
|
|
9
16
|
} from './clause_types';
|
|
10
17
|
import {BaseParser} from './base_parser';
|
|
@@ -24,10 +31,10 @@ export class StringParser extends BaseParser {
|
|
|
24
31
|
private tokenize(): void {
|
|
25
32
|
const specialSubstrings: SpecialToken[] = [{type: ',', value: ','}];
|
|
26
33
|
const specialWords: SpecialToken[] = [
|
|
27
|
-
{type: '
|
|
28
|
-
{type: '
|
|
29
|
-
{type: '
|
|
30
|
-
{type: '
|
|
34
|
+
{type: 'null', value: 'null', ignoreCase: true},
|
|
35
|
+
{type: 'empty', value: 'empty', ignoreCase: true},
|
|
36
|
+
{type: 'not_null', value: '-null', ignoreCase: true},
|
|
37
|
+
{type: 'not_empty', value: '-empty', ignoreCase: true},
|
|
31
38
|
];
|
|
32
39
|
const params: TokenizerParams = {
|
|
33
40
|
trimWordWhitespace: true,
|
|
@@ -44,89 +51,45 @@ export class StringParser extends BaseParser {
|
|
|
44
51
|
public parse(): StringParserResponse {
|
|
45
52
|
this.index = 0;
|
|
46
53
|
this.tokenize();
|
|
47
|
-
|
|
48
|
-
const
|
|
54
|
+
let clauses: StringClause[] = [];
|
|
55
|
+
const logs: FilterLog[] = [];
|
|
49
56
|
while (this.index < this.tokens.length) {
|
|
50
57
|
const token = this.getNext();
|
|
51
58
|
if (token.type === ',') {
|
|
59
|
+
if (this.index > 0 && this.tokens[this.index - 1].type === ',') {
|
|
60
|
+
logs.push({
|
|
61
|
+
severity: 'warn',
|
|
62
|
+
message: 'Empty clause',
|
|
63
|
+
startIndex: token.startIndex,
|
|
64
|
+
endIndex: token.endIndex,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
52
67
|
this.index++;
|
|
53
68
|
} else if (
|
|
54
|
-
token.type === '
|
|
55
|
-
token.type === '
|
|
56
|
-
token.type === '
|
|
57
|
-
token.type === '
|
|
69
|
+
token.type === 'null' ||
|
|
70
|
+
token.type === 'not_null' ||
|
|
71
|
+
token.type === 'empty' ||
|
|
72
|
+
token.type === 'not_empty'
|
|
58
73
|
) {
|
|
59
74
|
clauses.push({operator: token.type});
|
|
60
75
|
this.index++;
|
|
61
76
|
} else if (this.checkSimpleWord(clauses)) {
|
|
62
77
|
this.index++;
|
|
63
78
|
} else {
|
|
64
|
-
|
|
65
|
-
|
|
79
|
+
logs.push({
|
|
80
|
+
severity: 'warn',
|
|
81
|
+
message: 'Empty clause',
|
|
66
82
|
startIndex: token.startIndex,
|
|
67
83
|
endIndex: token.endIndex,
|
|
68
84
|
});
|
|
69
85
|
this.index++;
|
|
70
86
|
}
|
|
71
87
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
88
|
+
clauses = StringParser.groupClauses(clauses);
|
|
89
|
+
return {
|
|
90
|
+
clauses,
|
|
91
|
+
logs,
|
|
75
92
|
};
|
|
76
|
-
// const quotes: QuoteType[] = StringParser.findQuotes(this.inputString);
|
|
77
|
-
// if (quotes.length > 0) {
|
|
78
|
-
// response.quotes = quotes;
|
|
79
|
-
// }
|
|
80
|
-
return response;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
private static findQuotes(str: string): QuoteType[] {
|
|
84
|
-
const quotes: Set<QuoteType> = new Set();
|
|
85
|
-
let i = 0;
|
|
86
|
-
|
|
87
|
-
while (i < str.length) {
|
|
88
|
-
// Check for triple quotes first to avoid false positives
|
|
89
|
-
if (str.slice(i, i + 3) === "'''") {
|
|
90
|
-
quotes.add('TRIPLESINGLE');
|
|
91
|
-
i += 3;
|
|
92
|
-
} else if (str.slice(i, i + 3) === '"""') {
|
|
93
|
-
quotes.add('TRIPLEDOUBLE');
|
|
94
|
-
i += 3;
|
|
95
|
-
} else if (str[i] === '\\') {
|
|
96
|
-
// Check for escaped quotes
|
|
97
|
-
if (i + 1 < str.length) {
|
|
98
|
-
switch (str[i + 1]) {
|
|
99
|
-
case "'":
|
|
100
|
-
quotes.add('ESCAPEDSINGLE');
|
|
101
|
-
break;
|
|
102
|
-
case '"':
|
|
103
|
-
quotes.add('ESCAPEDDOUBLE');
|
|
104
|
-
break;
|
|
105
|
-
case '`':
|
|
106
|
-
quotes.add('ESCAPEDBACKTICK');
|
|
107
|
-
break;
|
|
108
|
-
}
|
|
109
|
-
i += 2;
|
|
110
|
-
} else {
|
|
111
|
-
i++;
|
|
112
|
-
}
|
|
113
|
-
} else {
|
|
114
|
-
// Check for single quotes
|
|
115
|
-
switch (str[i]) {
|
|
116
|
-
case "'":
|
|
117
|
-
quotes.add('SINGLE');
|
|
118
|
-
break;
|
|
119
|
-
case '"':
|
|
120
|
-
quotes.add('DOUBLE');
|
|
121
|
-
break;
|
|
122
|
-
case '`':
|
|
123
|
-
quotes.add('BACKTICK');
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
i++;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return Array.from(quotes);
|
|
130
93
|
}
|
|
131
94
|
|
|
132
95
|
private static groupClauses(clauses: StringClause[]): StringClause[] {
|
|
@@ -143,6 +106,12 @@ export class StringParser extends BaseParser {
|
|
|
143
106
|
'values' in current
|
|
144
107
|
) {
|
|
145
108
|
previous.values.push(...current.values);
|
|
109
|
+
} else if (
|
|
110
|
+
previous.operator === current.operator &&
|
|
111
|
+
'escaped_values' in previous &&
|
|
112
|
+
'escaped_values' in current
|
|
113
|
+
) {
|
|
114
|
+
previous.escaped_values.push(...current.escaped_values);
|
|
146
115
|
} else {
|
|
147
116
|
previous = current;
|
|
148
117
|
outputs.push(current);
|
|
@@ -178,23 +147,26 @@ export class StringParser extends BaseParser {
|
|
|
178
147
|
|
|
179
148
|
let operator: StringConditionOperator = negatedMatch ? '!=' : '=';
|
|
180
149
|
if (isUnderscore || isPercentMiddle || (isPercentBoth && word.length < 3)) {
|
|
181
|
-
|
|
150
|
+
// Special handling for string match
|
|
151
|
+
const matchOperator: StringMatchOperator = negatedMatch ? '!~' : '~';
|
|
152
|
+
if (word.length === 0) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
clauses.push({operator: matchOperator, escaped_values: [word]});
|
|
156
|
+
return true;
|
|
182
157
|
} else if (isPercentBoth && word.length > 2) {
|
|
183
|
-
operator = negatedMatch ? '
|
|
158
|
+
operator = negatedMatch ? 'not_contains' : 'contains';
|
|
184
159
|
word = word.substring(1, word.length - 1);
|
|
185
|
-
word = StringParser.removeBackslashes(word);
|
|
186
160
|
} else if (isPercentStart) {
|
|
187
|
-
operator = negatedMatch ? '
|
|
161
|
+
operator = negatedMatch ? 'not_ends' : 'ends';
|
|
188
162
|
word = word.substring(1, word.length);
|
|
189
|
-
word = StringParser.removeBackslashes(word);
|
|
190
163
|
} else if (isPercentEnd) {
|
|
191
|
-
operator = negatedMatch ? '
|
|
164
|
+
operator = negatedMatch ? 'not_starts' : 'starts';
|
|
192
165
|
word = word.substring(0, word.length - 1);
|
|
193
|
-
word = StringParser.removeBackslashes(word);
|
|
194
166
|
} else {
|
|
195
167
|
// = or !=
|
|
196
|
-
word = StringParser.removeBackslashes(word);
|
|
197
168
|
}
|
|
169
|
+
word = StringParser.removeBackslashes(word);
|
|
198
170
|
if (word.length === 0) {
|
|
199
171
|
return false;
|
|
200
172
|
}
|
package/src/string_serializer.ts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
1
8
|
import {
|
|
2
9
|
StringClause,
|
|
3
10
|
StringCondition,
|
|
4
11
|
StringConditionOperator,
|
|
12
|
+
StringMatch,
|
|
13
|
+
StringMatchOperator,
|
|
5
14
|
} from './clause_types';
|
|
6
15
|
|
|
7
16
|
export class StringSerializer {
|
|
@@ -16,11 +25,10 @@ export class StringSerializer {
|
|
|
16
25
|
|
|
17
26
|
private static isNegated(operator: StringConditionOperator): boolean {
|
|
18
27
|
return (
|
|
19
|
-
operator === '!~' ||
|
|
20
28
|
operator === '!=' ||
|
|
21
|
-
operator === '
|
|
22
|
-
operator === '
|
|
23
|
-
operator === '
|
|
29
|
+
operator === 'not_starts' ||
|
|
30
|
+
operator === 'not_ends' ||
|
|
31
|
+
operator === 'not_contains'
|
|
24
32
|
);
|
|
25
33
|
}
|
|
26
34
|
|
|
@@ -32,66 +40,84 @@ export class StringSerializer {
|
|
|
32
40
|
return input.replace(/[_%]/g, match => `\\${match}`);
|
|
33
41
|
}
|
|
34
42
|
|
|
35
|
-
// export type
|
|
43
|
+
// export type StringConditionOperator =
|
|
36
44
|
// | 'starts' | 'ends' | 'contains' | 'notStarts' | 'notEnds' | 'notContains'
|
|
37
|
-
// | '
|
|
45
|
+
// | '='| '!=';
|
|
38
46
|
private static StringConditionWordToString(
|
|
39
47
|
operator: StringConditionOperator,
|
|
40
48
|
value: string
|
|
41
49
|
): string {
|
|
42
50
|
const negated: boolean = StringSerializer.isNegated(operator);
|
|
43
|
-
if (value === '
|
|
51
|
+
if (value === 'null' || value === '-null') {
|
|
44
52
|
return (negated ? '-' : '') + '\\' + value;
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
value = StringSerializer.escapeSpecialCharacters(value);
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
value = StringSerializer.escapeWildcardCharacters(value);
|
|
57
|
+
if (operator === 'starts' || operator === 'not_starts') {
|
|
50
58
|
return (negated ? '-' : '') + value + '%';
|
|
51
|
-
} else if (operator === 'ends' || operator === '
|
|
52
|
-
value = StringSerializer.escapeWildcardCharacters(value);
|
|
59
|
+
} else if (operator === 'ends' || operator === 'not_ends') {
|
|
53
60
|
return (negated ? '-' : '') + '%' + value;
|
|
54
|
-
} else if (operator === 'contains' || operator === '
|
|
55
|
-
value = StringSerializer.escapeWildcardCharacters(value);
|
|
61
|
+
} else if (operator === 'contains' || operator === 'not_contains') {
|
|
56
62
|
return (negated ? '-' : '') + '%' + value + '%';
|
|
57
|
-
} else if (operator === '=' || operator === '!=') {
|
|
58
|
-
value = StringSerializer.escapeWildcardCharacters(value);
|
|
59
|
-
return (negated ? '-' : '') + value;
|
|
60
63
|
}
|
|
64
|
+
return (negated ? '-' : '') + value;
|
|
65
|
+
}
|
|
61
66
|
|
|
67
|
+
// export type StringMatchOperator = '~' | '!~';
|
|
68
|
+
private static StringMatchWordToString(
|
|
69
|
+
operator: StringMatchOperator,
|
|
70
|
+
value: string
|
|
71
|
+
): string {
|
|
72
|
+
const negated: boolean = operator === '!~' ? true : false;
|
|
73
|
+
if (value === 'null' || value === '-null') {
|
|
74
|
+
return (negated ? '-' : '') + '\\' + value;
|
|
75
|
+
}
|
|
76
|
+
value = StringSerializer.escapeSpecialCharacters(value);
|
|
62
77
|
return (negated ? '-' : '') + value;
|
|
63
78
|
}
|
|
64
79
|
|
|
65
80
|
private static StringClauseToString(
|
|
66
81
|
operator:
|
|
67
82
|
| StringConditionOperator
|
|
68
|
-
|
|
|
69
|
-
| '
|
|
70
|
-
| '
|
|
71
|
-
| '
|
|
83
|
+
| StringMatchOperator
|
|
84
|
+
| 'empty'
|
|
85
|
+
| 'not_empty'
|
|
86
|
+
| 'null'
|
|
87
|
+
| 'not_null',
|
|
72
88
|
clause: StringClause
|
|
73
89
|
): string {
|
|
74
|
-
if (operator === '
|
|
75
|
-
return '
|
|
76
|
-
} else if (operator === '
|
|
77
|
-
return '-
|
|
78
|
-
} else if (operator === '
|
|
79
|
-
return '
|
|
80
|
-
} else if (operator === '
|
|
81
|
-
return '-
|
|
82
|
-
}
|
|
83
|
-
if (!('values' in clause) || clause.values.length === 0) {
|
|
84
|
-
return '';
|
|
90
|
+
if (operator === 'empty') {
|
|
91
|
+
return 'empty';
|
|
92
|
+
} else if (operator === 'not_empty') {
|
|
93
|
+
return '-empty';
|
|
94
|
+
} else if (operator === 'null') {
|
|
95
|
+
return 'null';
|
|
96
|
+
} else if (operator === 'not_null') {
|
|
97
|
+
return '-null';
|
|
85
98
|
}
|
|
86
99
|
let result = '';
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
if ('values' in clause && clause.values.length > 0) {
|
|
101
|
+
const condition: StringCondition = clause;
|
|
102
|
+
for (const value of condition.values) {
|
|
103
|
+
const word = StringSerializer.StringConditionWordToString(
|
|
104
|
+
condition.operator,
|
|
105
|
+
value
|
|
106
|
+
);
|
|
107
|
+
if (word) {
|
|
108
|
+
result += word + ', ';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} else if ('escaped_values' in clause && clause.escaped_values.length > 0) {
|
|
112
|
+
const condition: StringMatch = clause;
|
|
113
|
+
for (const value of condition.escaped_values) {
|
|
114
|
+
const word = StringSerializer.StringMatchWordToString(
|
|
115
|
+
condition.operator,
|
|
116
|
+
value
|
|
117
|
+
);
|
|
118
|
+
if (word) {
|
|
119
|
+
result += word + ', ';
|
|
120
|
+
}
|
|
95
121
|
}
|
|
96
122
|
}
|
|
97
123
|
return result.trim().replace(/,$/, '');
|
package/src/token_types.ts
CHANGED
package/src/tokenizer.spec.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
1
8
|
import {Tokenizer, SpecialToken, TokenizerParams} from './tokenizer';
|
|
2
9
|
import {Token} from './token_types';
|
|
3
10
|
|
|
@@ -68,16 +75,16 @@ describe('Tokenizer', () => {
|
|
|
68
75
|
const input = 'hello NULL world,-Null,-\'NULL" ,NULL, NULL , ';
|
|
69
76
|
const expectedTokens = [
|
|
70
77
|
makeToken('word', 'hello', 0, 5),
|
|
71
|
-
makeToken('NULL', '
|
|
78
|
+
makeToken('NULL', 'null', 6, 10),
|
|
72
79
|
makeToken('word', 'world', 11, 16),
|
|
73
80
|
makeToken(',', ',', 16, 17),
|
|
74
|
-
makeToken('NOTNULL', '-
|
|
81
|
+
makeToken('NOTNULL', '-null', 17, 22),
|
|
75
82
|
makeToken(',', ',', 22, 23),
|
|
76
83
|
makeToken('word', '-\'NULL"', 23, 30),
|
|
77
84
|
makeToken(',', ',', 31, 32),
|
|
78
|
-
makeToken('NULL', '
|
|
85
|
+
makeToken('NULL', 'null', 32, 36),
|
|
79
86
|
makeToken(',', ',', 36, 37),
|
|
80
|
-
makeToken('NULL', '
|
|
87
|
+
makeToken('NULL', 'null', 38, 42),
|
|
81
88
|
makeToken(',', ',', 43, 44),
|
|
82
89
|
];
|
|
83
90
|
const params = makeParams();
|
|
@@ -121,18 +128,18 @@ describe('Tokenizer', () => {
|
|
|
121
128
|
];
|
|
122
129
|
expect(new Tokenizer(input, makeParams()).parse()).toEqual(expectedTokens);
|
|
123
130
|
});
|
|
124
|
-
it('should match regexp and
|
|
131
|
+
it('should match regexp and lowercase special matches', () => {
|
|
125
132
|
const input =
|
|
126
133
|
"hello tuesDAY,ttuesday, tuesdayy ,Tuesday , ttuesday, 'TUESday' ";
|
|
127
134
|
const expectedTokens = [
|
|
128
135
|
makeToken('word', 'hello', 0, 5),
|
|
129
|
-
makeToken('DAYOFWEEK', '
|
|
136
|
+
makeToken('DAYOFWEEK', 'tuesday', 6, 13),
|
|
130
137
|
makeToken(',', ',', 13, 14),
|
|
131
138
|
makeToken('word', 'ttuesday', 14, 22),
|
|
132
139
|
makeToken(',', ',', 22, 23),
|
|
133
140
|
makeToken('word', 'tuesdayy', 24, 32),
|
|
134
141
|
makeToken(',', ',', 33, 34),
|
|
135
|
-
makeToken('DAYOFWEEK', '
|
|
142
|
+
makeToken('DAYOFWEEK', 'tuesday', 34, 41),
|
|
136
143
|
makeToken(',', ',', 42, 43),
|
|
137
144
|
makeToken('word', 'ttuesday', 44, 52),
|
|
138
145
|
makeToken(',', ',', 52, 53),
|
package/src/tokenizer.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
1
8
|
import {Token} from './token_types';
|
|
2
9
|
|
|
3
10
|
export interface SpecialToken {
|
|
@@ -138,7 +145,7 @@ export class Tokenizer {
|
|
|
138
145
|
: subString === special.value;
|
|
139
146
|
if (matches) {
|
|
140
147
|
const value = special.ignoreCase
|
|
141
|
-
? subString.
|
|
148
|
+
? subString.toLowerCase()
|
|
142
149
|
: subString;
|
|
143
150
|
return {
|
|
144
151
|
type: special.type,
|
|
@@ -205,7 +212,7 @@ export class Tokenizer {
|
|
|
205
212
|
regexp.lastIndex = 0; // Set the starting index for the search
|
|
206
213
|
if (regexp.test(token.value)) {
|
|
207
214
|
const value = special.ignoreCase
|
|
208
|
-
? token.value.
|
|
215
|
+
? token.value.toLowerCase()
|
|
209
216
|
: token.value;
|
|
210
217
|
return {
|
|
211
218
|
type: special.type,
|
|
@@ -220,7 +227,7 @@ export class Tokenizer {
|
|
|
220
227
|
: token.value === special.value;
|
|
221
228
|
if (matches) {
|
|
222
229
|
const value = special.ignoreCase
|
|
223
|
-
? token.value.
|
|
230
|
+
? token.value.toLowerCase()
|
|
224
231
|
: token.value;
|
|
225
232
|
return {
|
|
226
233
|
type: special.type,
|