@witchcraft/expressit 0.0.2 → 0.1.0
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/README.md +6 -4
- package/dist/Lexer.d.ts +146 -0
- package/dist/Lexer.d.ts.map +1 -0
- package/dist/Lexer.js +960 -0
- package/dist/Parser.d.ts +140 -0
- package/dist/Parser.d.ts.map +1 -0
- package/dist/Parser.js +668 -0
- package/dist/ast/builders/token.js +1 -1
- package/dist/ast/handlers.d.ts +3 -3
- package/dist/ast/handlers.d.ts.map +1 -1
- package/dist/ast/index.d.ts.map +1 -1
- package/dist/examples/index.d.ts +2 -0
- package/dist/examples/index.d.ts.map +1 -0
- package/dist/examples/index.js +4 -0
- package/dist/examples/shortcutContextParser.d.ts +2 -1
- package/dist/examples/shortcutContextParser.d.ts.map +1 -1
- package/dist/examples/shortcutContextParser.js +9 -5
- package/dist/helpers/errors.d.ts.map +1 -1
- package/dist/helpers/errors.js +3 -1
- package/dist/helpers/index.d.ts.map +1 -1
- package/dist/helpers/parser/checkParserOpts.d.ts.map +1 -1
- package/dist/helpers/parser/checkParserOpts.js +3 -2
- package/dist/helpers/parser/extractPosition.d.ts +2 -6
- package/dist/helpers/parser/extractPosition.d.ts.map +1 -1
- package/dist/helpers/parser/extractPosition.js +3 -3
- package/dist/helpers/parser/getUnclosedRightParenCount.d.ts +2 -3
- package/dist/helpers/parser/getUnclosedRightParenCount.d.ts.map +1 -1
- package/dist/helpers/parser/getUnclosedRightParenCount.js +4 -4
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -5
- package/dist/methods/autocomplete.d.ts.map +1 -1
- package/dist/methods/autocomplete.js +1 -1
- package/dist/methods/autoreplace.js +1 -1
- package/dist/methods/autosuggest.js +1 -1
- package/dist/methods/evaluate.d.ts.map +1 -1
- package/dist/methods/evaluate.js +3 -1
- package/dist/methods/getIndexes.d.ts.map +1 -1
- package/dist/methods/getIndexes.js +2 -1
- package/dist/methods/normalize.d.ts +0 -2
- package/dist/methods/normalize.d.ts.map +1 -1
- package/dist/methods/normalize.js +2 -3
- package/dist/methods/validate.d.ts.map +1 -1
- package/dist/methods/validate.js +3 -1
- package/dist/package.json.js +44 -37
- package/dist/types/ast.d.ts +2 -8
- package/dist/types/ast.d.ts.map +1 -1
- package/dist/types/errors.d.ts +5 -17
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/errors.js +0 -1
- package/dist/types/parser.d.ts +6 -2
- package/dist/types/parser.d.ts.map +1 -1
- package/dist/utils/extractTokens.js +1 -1
- package/dist/utils/getCursorInfo.d.ts +2 -2
- package/dist/utils/getCursorInfo.d.ts.map +1 -1
- package/dist/utils/getCursorInfo.js +3 -2
- package/dist/utils/getOppositeDelimiter.d.ts.map +1 -1
- package/dist/utils/getOppositeDelimiter.js +1 -1
- package/dist/utils/prettyAst.d.ts.map +1 -1
- package/dist/utils/prettyAst.js +15 -9
- package/package.json +42 -37
- package/src/Lexer.ts +704 -0
- package/src/Parser.ts +972 -0
- package/src/ast/builders/array.ts +2 -2
- package/src/ast/builders/condition.ts +1 -1
- package/src/ast/builders/expression.ts +1 -1
- package/src/ast/builders/group.ts +1 -1
- package/src/ast/builders/index.ts +1 -1
- package/src/ast/builders/pos.ts +1 -1
- package/src/ast/builders/token.ts +2 -2
- package/src/ast/builders/type.ts +1 -1
- package/src/ast/builders/variable.ts +1 -1
- package/src/ast/classes/ConditionNode.ts +1 -1
- package/src/ast/classes/ErrorToken.ts +1 -1
- package/src/ast/classes/ValidToken.ts +2 -2
- package/src/ast/classes/index.ts +1 -1
- package/src/ast/handlers.ts +6 -6
- package/src/ast/index.ts +2 -2
- package/src/examples/index.ts +3 -0
- package/src/examples/shortcutContextParser.ts +11 -6
- package/src/helpers/errors.ts +5 -3
- package/src/helpers/general/defaultConditionNormalizer.ts +1 -1
- package/src/helpers/general/index.ts +1 -1
- package/src/helpers/index.ts +3 -2
- package/src/helpers/parser/checkParserOpts.ts +13 -12
- package/src/helpers/parser/extractPosition.ts +4 -8
- package/src/helpers/parser/getUnclosedRightParenCount.ts +6 -6
- package/src/helpers/parser/index.ts +1 -1
- package/src/helpers/parser/parseParserOptions.ts +1 -1
- package/src/index.ts +2 -2
- package/src/methods/autocomplete.ts +5 -5
- package/src/methods/autoreplace.ts +2 -2
- package/src/methods/autosuggest.ts +3 -3
- package/src/methods/evaluate.ts +4 -2
- package/src/methods/getIndexes.ts +2 -1
- package/src/methods/normalize.ts +3 -4
- package/src/methods/validate.ts +4 -2
- package/src/types/ast.ts +2 -9
- package/src/types/errors.ts +12 -22
- package/src/types/parser.ts +6 -4
- package/src/utils/extractTokens.ts +1 -1
- package/src/utils/getCursorInfo.ts +6 -4
- package/src/utils/getOppositeDelimiter.ts +5 -2
- package/src/utils/prettyAst.ts +5 -3
- package/dist/examples/advancedValueComparer.d.ts +0 -3
- package/dist/examples/advancedValueComparer.d.ts.map +0 -1
- package/dist/examples/advancedValueComparer.js +0 -28
- package/dist/grammar/ParserBase.d.ts +0 -51
- package/dist/grammar/ParserBase.d.ts.map +0 -1
- package/dist/grammar/ParserBase.js +0 -516
- package/dist/grammar/createTokens.d.ts +0 -56
- package/dist/grammar/createTokens.d.ts.map +0 -1
- package/dist/grammar/createTokens.js +0 -843
- package/dist/grammar/index.d.ts +0 -3
- package/dist/grammar/index.d.ts.map +0 -1
- package/dist/grammar/index.js +0 -6
- package/dist/parser.d.ts +0 -58
- package/dist/parser.d.ts.map +0 -1
- package/dist/parser.js +0 -136
- package/src/examples/advancedValueComparer.ts +0 -31
- package/src/grammar/ParserBase.ts +0 -715
- package/src/grammar/createTokens.ts +0 -512
- package/src/grammar/index.ts +0 -4
- package/src/parser.ts +0 -183
|
@@ -1,512 +0,0 @@
|
|
|
1
|
-
/* eslint-disable camelcase */
|
|
2
|
-
import { escapeRegex, isBlank } from "@alanscodelog/utils"
|
|
3
|
-
import { createToken, Lexer, type TokenType } from "chevrotain"
|
|
4
|
-
|
|
5
|
-
import type { FullParserOptions } from "../types/parser.js"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/** Makes it easier to rename the tokens while still returning a properly typed record of them.*/
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
10
|
-
enum $T {
|
|
11
|
-
_ = "_", // whitespace,
|
|
12
|
-
ANY = "ANY",
|
|
13
|
-
QUOTE_ANY = "QUOTE_ANY",
|
|
14
|
-
QUOTE_SINGLE = "QUOTE_SINGLE",
|
|
15
|
-
QUOTE_DOUBLE = "QUOTE_DOUBLE",
|
|
16
|
-
QUOTE_BACKTICK = "QUOTE_BACKTICK",
|
|
17
|
-
VALUE = "VALUE",
|
|
18
|
-
REGEX_ANY = "REGEX_ANY",
|
|
19
|
-
VALUE_UNQUOTED = "VALUE_UNQUOTED",
|
|
20
|
-
BRACKET_VALUE_UNQUOTED = "BRACKET_VALUE_UNQUOTED",
|
|
21
|
-
VALUE_REGEX = "VALUE_REGEX",
|
|
22
|
-
VALUE_NOT_SINGLE = "VALUE_NOT_SINGLE",
|
|
23
|
-
VALUE_NOT_DOUBLE = "VALUE_NOT_DOUBLE",
|
|
24
|
-
VALUE_NOT_BACKTICK = "VALUE_NOT_BACKTICK",
|
|
25
|
-
VALUE_FOR_SINGLE = "VALUE_FOR_SINGLE",
|
|
26
|
-
VALUE_FOR_DOUBLE = "VALUE_FOR_DOUBLE",
|
|
27
|
-
VALUE_FOR_BACKTICK = "VALUE_FOR_BACKTICK",
|
|
28
|
-
OPERATOR_OR = "OPERATOR_OR",
|
|
29
|
-
OPERATOR_AND = "OPERATOR_AND",
|
|
30
|
-
OPERATOR_NOT = "OPERATOR_NOT",
|
|
31
|
-
SYM_OR = "SYM_OR",
|
|
32
|
-
SYM_AND = "SYM_AND",
|
|
33
|
-
SYM_NOT = "SYM_NOT",
|
|
34
|
-
WORD_OR = "WORD_OR",
|
|
35
|
-
WORD_AND = "WORD_AND",
|
|
36
|
-
WORD_NOT = "WORD_NOT",
|
|
37
|
-
REGEX_START = "REGEX_START",
|
|
38
|
-
REGEX_END = "REGEX_END",
|
|
39
|
-
QUOTE_SINGLE_START = "QUOTE_SINGLE_START",
|
|
40
|
-
QUOTE_DOUBLE_START = "QUOTE_DOUBLE_START",
|
|
41
|
-
QUOTE_BACKTICK_START = "QUOTE_BACKTICK_START",
|
|
42
|
-
QUOTE_SINGLE_END = "QUOTE_SINGLE_END",
|
|
43
|
-
QUOTE_DOUBLE_END = "QUOTE_DOUBLE_END",
|
|
44
|
-
QUOTE_BACKTICK_END = "QUOTE_BACKTICK_END",
|
|
45
|
-
EXP_PROP_OP = "EXP_PROP_OP",
|
|
46
|
-
CUSTOM_PROP_OP = "CUSTOM_PROP_OP",
|
|
47
|
-
PAREN_L = "PAREN_L",
|
|
48
|
-
PAREN_R = "PAREN_R",
|
|
49
|
-
BRACKET_L = "BRACKET_L",
|
|
50
|
-
BRACKET_R = "BRACKET_R",
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Should only be used internally by the lexer.
|
|
54
|
-
type LexerOnly =
|
|
55
|
-
// | $T.ANY - special case, needed when we want to consume any token
|
|
56
|
-
| $T.VALUE_NOT_BACKTICK
|
|
57
|
-
| $T.VALUE_NOT_DOUBLE
|
|
58
|
-
| $T.VALUE_NOT_SINGLE
|
|
59
|
-
| $T.SYM_OR
|
|
60
|
-
| $T.SYM_AND
|
|
61
|
-
| $T.WORD_OR
|
|
62
|
-
| $T.WORD_AND
|
|
63
|
-
// | $T.REGEX_START - special case, needed for recovering
|
|
64
|
-
| $T.REGEX_END
|
|
65
|
-
| $T.QUOTE_SINGLE_START
|
|
66
|
-
| $T.QUOTE_DOUBLE_START
|
|
67
|
-
| $T.QUOTE_BACKTICK_START
|
|
68
|
-
| $T.QUOTE_SINGLE_END
|
|
69
|
-
| $T.QUOTE_DOUBLE_END
|
|
70
|
-
| $T.QUOTE_BACKTICK_END
|
|
71
|
-
| $T.WORD_NOT
|
|
72
|
-
// | $T.SYM_NOT - special case, allowed because custom prop operators can be the "symbol" negation tokens
|
|
73
|
-
|
|
74
|
-
function clone(token: TokenType): TokenType {
|
|
75
|
-
const t: any = {}
|
|
76
|
-
if (token.name !== undefined) t.name = token.name
|
|
77
|
-
if (token.CATEGORIES !== undefined) t.categories = token.CATEGORIES
|
|
78
|
-
if (token.GROUP !== undefined) t.group = token.GROUP
|
|
79
|
-
if (token.LINE_BREAKS !== undefined) t.line_breaks = token.LINE_BREAKS
|
|
80
|
-
if (token.LONGER_ALT !== undefined) t.longet_alt = token.LONGER_ALT
|
|
81
|
-
if (token.PATTERN !== undefined) t.pattern = token.PATTERN
|
|
82
|
-
if (token.PUSH_MODE !== undefined) t.push_mode = token.PUSH_MODE
|
|
83
|
-
if (token.POP_MODE !== undefined) t.pop_mode = token.POP_MODE
|
|
84
|
-
return createToken(t)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function changePushMode(tokens: TokenType[], mode: string | undefined | ((str?: string) => string)): TokenType[] {
|
|
88
|
-
return tokens.map(_ => clone({
|
|
89
|
-
..._,
|
|
90
|
-
...(mode ? { PUSH_MODE: typeof mode === "function" ? mode(_.PUSH_MODE) : mode } : {}),
|
|
91
|
-
}))
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function createTokens<T extends {} = {}>(opts: FullParserOptions<T>): {
|
|
95
|
-
tokens: Record<Exclude<$T, LexerOnly>, TokenType>
|
|
96
|
-
lexer: Lexer
|
|
97
|
-
info: {
|
|
98
|
-
expandedSepAlsoCustom: boolean
|
|
99
|
-
customOpAlsoNegation: boolean
|
|
100
|
-
}
|
|
101
|
-
} {
|
|
102
|
-
const $: Record<$T, TokenType> = {} as any
|
|
103
|
-
|
|
104
|
-
/* #region TOKEN CATEGORIES */
|
|
105
|
-
|
|
106
|
-
$[$T.ANY] = createToken({
|
|
107
|
-
name: $T.ANY,
|
|
108
|
-
pattern: Lexer.NA,
|
|
109
|
-
})
|
|
110
|
-
$[$T.QUOTE_ANY] = createToken({
|
|
111
|
-
name: $T.QUOTE_ANY,
|
|
112
|
-
pattern: Lexer.NA,
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
// so we can easily match start/end tokens in wrong positions
|
|
116
|
-
$[$T.QUOTE_SINGLE] = createToken({
|
|
117
|
-
name: $T.QUOTE_SINGLE,
|
|
118
|
-
pattern: Lexer.NA,
|
|
119
|
-
})
|
|
120
|
-
$[$T.QUOTE_DOUBLE] = createToken({
|
|
121
|
-
name: $T.QUOTE_DOUBLE,
|
|
122
|
-
pattern: Lexer.NA,
|
|
123
|
-
})
|
|
124
|
-
$[$T.QUOTE_BACKTICK] = createToken({
|
|
125
|
-
name: $T.QUOTE_BACKTICK,
|
|
126
|
-
pattern: Lexer.NA,
|
|
127
|
-
})
|
|
128
|
-
$[$T.REGEX_ANY] = createToken({
|
|
129
|
-
name: $T.REGEX_ANY,
|
|
130
|
-
pattern: Lexer.NA,
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
// required to make bracket values work
|
|
134
|
-
// see the bracket modes at the end for an explanation
|
|
135
|
-
$[$T.VALUE_FOR_SINGLE] = createToken({
|
|
136
|
-
name: $T.VALUE_FOR_SINGLE,
|
|
137
|
-
pattern: Lexer.NA,
|
|
138
|
-
})
|
|
139
|
-
$[$T.VALUE_FOR_DOUBLE] = createToken({
|
|
140
|
-
name: $T.VALUE_FOR_DOUBLE,
|
|
141
|
-
pattern: Lexer.NA,
|
|
142
|
-
})
|
|
143
|
-
$[$T.VALUE_FOR_BACKTICK] = createToken({
|
|
144
|
-
name: $T.VALUE_FOR_BACKTICK,
|
|
145
|
-
pattern: Lexer.NA,
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
$[$T.OPERATOR_OR] = createToken({
|
|
149
|
-
name: $T.OPERATOR_OR,
|
|
150
|
-
pattern: Lexer.NA,
|
|
151
|
-
})
|
|
152
|
-
$[$T.OPERATOR_AND] = createToken({
|
|
153
|
-
name: $T.OPERATOR_AND,
|
|
154
|
-
pattern: Lexer.NA,
|
|
155
|
-
})
|
|
156
|
-
$[$T.OPERATOR_NOT] = createToken({
|
|
157
|
-
name: $T.OPERATOR_NOT,
|
|
158
|
-
pattern: Lexer.NA,
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
$[$T.VALUE] = createToken({
|
|
162
|
-
name: $T.VALUE,
|
|
163
|
-
pattern: Lexer.NA,
|
|
164
|
-
})
|
|
165
|
-
/* #regionend */
|
|
166
|
-
/* #region ACTUAL TOKENS */
|
|
167
|
-
|
|
168
|
-
$[$T._] = createToken({
|
|
169
|
-
name: $T._,
|
|
170
|
-
pattern: /\s+/,
|
|
171
|
-
group: Lexer.SKIPPED,
|
|
172
|
-
line_breaks: true,
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
$[$T.REGEX_START] = createToken({
|
|
177
|
-
name: $T.REGEX_START,
|
|
178
|
-
push_mode: "notRegex",
|
|
179
|
-
pattern: /\//,
|
|
180
|
-
categories: [$[$T.REGEX_ANY], $[$T.ANY]],
|
|
181
|
-
})
|
|
182
|
-
$[$T.REGEX_END] = createToken({
|
|
183
|
-
name: $T.REGEX_END,
|
|
184
|
-
push_mode: "main",
|
|
185
|
-
pattern: /\/[a-z]*/,
|
|
186
|
-
categories: [$[$T.REGEX_ANY], $[$T.ANY]],
|
|
187
|
-
})
|
|
188
|
-
$[$T.VALUE_REGEX] = createToken({
|
|
189
|
-
name: $T.VALUE_REGEX,
|
|
190
|
-
push_mode: "regexEnd",
|
|
191
|
-
line_breaks: true,
|
|
192
|
-
categories: [$[$T.ANY]],
|
|
193
|
-
pattern: {
|
|
194
|
-
exec: (text, start) => {
|
|
195
|
-
let end = start
|
|
196
|
-
let inGroup = 0
|
|
197
|
-
let char = text[end]
|
|
198
|
-
let prevEscaped = false
|
|
199
|
-
while (char !== undefined && (char !== "/" || inGroup > 0 || prevEscaped)) {
|
|
200
|
-
if (char === "[") inGroup++
|
|
201
|
-
// normally something like /][/ will error, but we pretend the initial "negative" ] are ignored so things like /][]/ won't
|
|
202
|
-
if (char === "]" && inGroup > 0) inGroup--
|
|
203
|
-
if (char === "\\") {
|
|
204
|
-
if (!prevEscaped) {
|
|
205
|
-
prevEscaped = true
|
|
206
|
-
} else {
|
|
207
|
-
prevEscaped = false
|
|
208
|
-
}
|
|
209
|
-
} else {
|
|
210
|
-
prevEscaped &&= false
|
|
211
|
-
}
|
|
212
|
-
end++
|
|
213
|
-
char = text[end]
|
|
214
|
-
}
|
|
215
|
-
if (start === end) return null
|
|
216
|
-
return [text.substring(start, end)]
|
|
217
|
-
},
|
|
218
|
-
},
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
$[$T.QUOTE_SINGLE_START] = createToken({
|
|
223
|
-
name: $T.QUOTE_SINGLE_START,
|
|
224
|
-
pattern: /'/,
|
|
225
|
-
push_mode: "notSingle",
|
|
226
|
-
categories: [$[$T.QUOTE_SINGLE], $[$T.QUOTE_ANY], $[$T.ANY]],
|
|
227
|
-
})
|
|
228
|
-
$[$T.QUOTE_DOUBLE_START] = createToken({
|
|
229
|
-
name: $T.QUOTE_DOUBLE_START,
|
|
230
|
-
pattern: /"/,
|
|
231
|
-
push_mode: "notDouble",
|
|
232
|
-
categories: [$[$T.QUOTE_DOUBLE], $[$T.QUOTE_ANY], $[$T.ANY]],
|
|
233
|
-
})
|
|
234
|
-
$[$T.QUOTE_BACKTICK_START] = createToken({
|
|
235
|
-
name: $T.QUOTE_BACKTICK_START,
|
|
236
|
-
pattern: /`/,
|
|
237
|
-
push_mode: "notBacktick",
|
|
238
|
-
categories: [$[$T.QUOTE_BACKTICK], $[$T.QUOTE_ANY], $[$T.ANY]],
|
|
239
|
-
})
|
|
240
|
-
$[$T.QUOTE_SINGLE_END] = createToken({
|
|
241
|
-
name: $T.QUOTE_SINGLE_END,
|
|
242
|
-
pattern: /'/,
|
|
243
|
-
push_mode: "main",
|
|
244
|
-
categories: [$[$T.QUOTE_SINGLE], $[$T.QUOTE_ANY], $[$T.ANY]],
|
|
245
|
-
})
|
|
246
|
-
$[$T.QUOTE_DOUBLE_END] = createToken({
|
|
247
|
-
name: $T.QUOTE_DOUBLE_END,
|
|
248
|
-
pattern: /"/,
|
|
249
|
-
push_mode: "main",
|
|
250
|
-
categories: [$[$T.QUOTE_DOUBLE], $[$T.QUOTE_ANY], $[$T.ANY]],
|
|
251
|
-
})
|
|
252
|
-
$[$T.QUOTE_BACKTICK_END] = createToken({
|
|
253
|
-
name: $T.QUOTE_BACKTICK_END,
|
|
254
|
-
pattern: /`/,
|
|
255
|
-
push_mode: "main",
|
|
256
|
-
categories: [$[$T.QUOTE_BACKTICK], $[$T.QUOTE_ANY], $[$T.ANY]],
|
|
257
|
-
})
|
|
258
|
-
$[$T.VALUE_NOT_SINGLE] = createToken({
|
|
259
|
-
name: $T.VALUE_NOT_SINGLE,
|
|
260
|
-
pattern: /(\\[\s\S]|[^'])+/,
|
|
261
|
-
push_mode: "endQuotes",
|
|
262
|
-
categories: [$[$T.VALUE], $[$T.VALUE_FOR_SINGLE], $[$T.ANY]],
|
|
263
|
-
line_breaks: true,
|
|
264
|
-
})
|
|
265
|
-
$[$T.VALUE_NOT_DOUBLE] = createToken({
|
|
266
|
-
name: $T.VALUE_NOT_DOUBLE,
|
|
267
|
-
pattern: /(\\[\s\S]|[^"])+/,
|
|
268
|
-
push_mode: "endQuotes",
|
|
269
|
-
categories: [$[$T.VALUE], $[$T.VALUE_FOR_DOUBLE], $[$T.ANY]],
|
|
270
|
-
line_breaks: true,
|
|
271
|
-
})
|
|
272
|
-
$[$T.VALUE_NOT_BACKTICK] = createToken({
|
|
273
|
-
name: $T.VALUE_NOT_BACKTICK,
|
|
274
|
-
pattern: /(\\[\s\S]|[^`])+/,
|
|
275
|
-
push_mode: "endQuotes",
|
|
276
|
-
categories: [$[$T.VALUE], $[$T.VALUE_FOR_BACKTICK], $[$T.ANY]],
|
|
277
|
-
line_breaks: true,
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
const symOrs = opts.keywords.or.filter(_ => _.isSymbol).map(_ => escapeRegex(_.value))
|
|
281
|
-
const symAnds = opts.keywords.and.filter(_ => _.isSymbol).map(_ => escapeRegex(_.value))
|
|
282
|
-
const symNots = opts.keywords.not.filter(_ => _.isSymbol).map(_ => escapeRegex(_.value))
|
|
283
|
-
const wordOrs = opts.keywords.or.filter(_ => !_.isSymbol).map(_ => escapeRegex(_.value))
|
|
284
|
-
const wordAnds = opts.keywords.and.filter(_ => !_.isSymbol).map(_ => escapeRegex(_.value))
|
|
285
|
-
const wordNots = opts.keywords.not.filter(_ => !_.isSymbol).map(_ => escapeRegex(_.value))
|
|
286
|
-
let syms = [...symOrs, ...symAnds, ...symNots]
|
|
287
|
-
|
|
288
|
-
const customPropertyOperators = (opts.customPropertyOperators ?? []).map(_ => escapeRegex(_))
|
|
289
|
-
|
|
290
|
-
const expandedPropertySeparator = escapeRegex(opts.expandedPropertySeparator ?? "")
|
|
291
|
-
|
|
292
|
-
if (expandedPropertySeparator) syms.push(expandedPropertySeparator)
|
|
293
|
-
if (customPropertyOperators) syms = syms.concat(customPropertyOperators)
|
|
294
|
-
if (opts.regexValues) syms.push("\\/")
|
|
295
|
-
if (opts.arrayValues) {
|
|
296
|
-
syms.push("\\[")
|
|
297
|
-
// [ makes the lexer enter a bracket value, but ] should not be ignored by VALUE_UNQUOTED in case we get input like just `]` or `...]` which should be parsed as values
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// future change to custom pattern, should be faster
|
|
301
|
-
$[$T.VALUE_UNQUOTED] = createToken({
|
|
302
|
-
name: $T.VALUE_UNQUOTED,
|
|
303
|
-
pattern: new RegExp(`(\\\\[\\s\\S]|(${syms.length > 0 ? `(?!(${syms.join("|")}))` : ``}[^ \\t()'"\`\\\\]))+`),
|
|
304
|
-
push_mode: "endQuotes",
|
|
305
|
-
categories: [$[$T.VALUE], $[$T.ANY]],
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
$[$T.BRACKET_VALUE_UNQUOTED] = createToken({
|
|
309
|
-
name: $T.BRACKET_VALUE_UNQUOTED,
|
|
310
|
-
pattern: /(\\[\s\S]|([^ \]\\t'"`\\]))+/,
|
|
311
|
-
push_mode: "bracket_endQuotes",
|
|
312
|
-
categories: [$[$T.VALUE], $[$T.ANY]],
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
// operators are only added if they're enabled, otherwise cheverotain will complain about empty regex expressions
|
|
316
|
-
const operators = []
|
|
317
|
-
|
|
318
|
-
$[$T.SYM_OR] = createToken({
|
|
319
|
-
name: $T.SYM_OR,
|
|
320
|
-
pattern: new RegExp(`(${symOrs.join("|")})`),
|
|
321
|
-
categories: [$[$T.OPERATOR_OR], $[$T.ANY]],
|
|
322
|
-
})
|
|
323
|
-
if (symOrs.length > 0) operators.push($[$T.SYM_OR])
|
|
324
|
-
|
|
325
|
-
$[$T.SYM_AND] = createToken({
|
|
326
|
-
name: $T.SYM_AND,
|
|
327
|
-
pattern: new RegExp(`(${symAnds.join("|")})`),
|
|
328
|
-
categories: [$[$T.OPERATOR_AND], $[$T.ANY]],
|
|
329
|
-
})
|
|
330
|
-
if (symAnds.length > 0) operators.push($[$T.SYM_AND])
|
|
331
|
-
|
|
332
|
-
$[$T.SYM_NOT] = createToken({
|
|
333
|
-
name: $T.SYM_NOT,
|
|
334
|
-
pattern: new RegExp(`(${symNots.join("|")})`),
|
|
335
|
-
categories: [$[$T.OPERATOR_NOT], $[$T.ANY]],
|
|
336
|
-
})
|
|
337
|
-
if (symNots.length > 0) operators.push($[$T.SYM_NOT])
|
|
338
|
-
|
|
339
|
-
$[$T.WORD_OR] = createToken({
|
|
340
|
-
name: $T.WORD_OR,
|
|
341
|
-
pattern: new RegExp(`(${wordOrs.join("|")})`),
|
|
342
|
-
longer_alt: $[$T.VALUE_UNQUOTED],
|
|
343
|
-
categories: [$[$T.OPERATOR_OR], $[$T.ANY]],
|
|
344
|
-
})
|
|
345
|
-
if (wordOrs.length > 0) operators.push($[$T.WORD_OR])
|
|
346
|
-
|
|
347
|
-
$[$T.WORD_AND] = createToken({
|
|
348
|
-
name: $T.WORD_AND,
|
|
349
|
-
pattern: new RegExp(`(${wordAnds.join("|")})`),
|
|
350
|
-
longer_alt: $[$T.VALUE_UNQUOTED],
|
|
351
|
-
categories: [$[$T.OPERATOR_AND], $[$T.ANY]],
|
|
352
|
-
})
|
|
353
|
-
if (wordAnds.length > 0) operators.push($[$T.WORD_AND])
|
|
354
|
-
|
|
355
|
-
$[$T.WORD_NOT] = createToken({
|
|
356
|
-
name: $T.WORD_NOT,
|
|
357
|
-
pattern: new RegExp(`(${wordNots.join("|")})`),
|
|
358
|
-
longer_alt: $[$T.VALUE_UNQUOTED],
|
|
359
|
-
categories: [$[$T.OPERATOR_NOT], $[$T.ANY]],
|
|
360
|
-
})
|
|
361
|
-
if (wordNots.length > 0) operators.push($[$T.WORD_NOT])
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
/* region Operators */
|
|
365
|
-
$[$T.EXP_PROP_OP] = createToken({
|
|
366
|
-
name: $T.EXP_PROP_OP,
|
|
367
|
-
pattern: new RegExp(`${expandedPropertySeparator}`),
|
|
368
|
-
categories: [$[$T.ANY]],
|
|
369
|
-
})
|
|
370
|
-
|
|
371
|
-
if (!isBlank(expandedPropertySeparator)) operators.splice(0, 0, $[$T.EXP_PROP_OP])
|
|
372
|
-
|
|
373
|
-
$[$T.CUSTOM_PROP_OP] = createToken({
|
|
374
|
-
name: $T.CUSTOM_PROP_OP,
|
|
375
|
-
pattern: new RegExp(`(${customPropertyOperators.join("|")})`),
|
|
376
|
-
categories: [$[$T.ANY]],
|
|
377
|
-
})
|
|
378
|
-
|
|
379
|
-
// only add custom operator if it's pattern doesn't match the not or expanded operator separator patterns (which can be the same)
|
|
380
|
-
// otherwise chevrotain will complain when the regex patterns match exactly
|
|
381
|
-
const customOpEqualsExpandedOrNegationToken = [$[$T.SYM_NOT].PATTERN, $[$T.EXP_PROP_OP].PATTERN]
|
|
382
|
-
.find(_ => _?.toString() === $[$T.CUSTOM_PROP_OP].PATTERN?.toString()) !== undefined
|
|
383
|
-
|
|
384
|
-
if (
|
|
385
|
-
(customPropertyOperators?.length ?? 0) > 0 &&
|
|
386
|
-
!customOpEqualsExpandedOrNegationToken
|
|
387
|
-
) operators.splice(1, 0, $[$T.CUSTOM_PROP_OP])
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
// for parser
|
|
391
|
-
const expandedSepAlsoCustom = customPropertyOperators.includes(expandedPropertySeparator)
|
|
392
|
-
const customOpAlsoNegation = symNots.length > 0 &&
|
|
393
|
-
customPropertyOperators?.find(_ => symNots.includes(_)) !== undefined
|
|
394
|
-
/* regionend */
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
$[$T.PAREN_L] = createToken({
|
|
398
|
-
name: $T.PAREN_L,
|
|
399
|
-
pattern: /\(/,
|
|
400
|
-
categories: [$[$T.ANY]],
|
|
401
|
-
})
|
|
402
|
-
$[$T.PAREN_R] = createToken({
|
|
403
|
-
name: $T.PAREN_R,
|
|
404
|
-
pattern: /\)/,
|
|
405
|
-
categories: [$[$T.ANY]],
|
|
406
|
-
})
|
|
407
|
-
const parens = [$[$T.PAREN_L], $[$T.PAREN_R]]
|
|
408
|
-
// they still need to be defined for the parser, but if opts.arrayValues is false, they're never in any of the lexer modes
|
|
409
|
-
$[$T.BRACKET_L] = createToken({
|
|
410
|
-
name: $T.BRACKET_L,
|
|
411
|
-
pattern: /\[/,
|
|
412
|
-
push_mode: "bracket_main",
|
|
413
|
-
categories: [$[$T.ANY]],
|
|
414
|
-
})
|
|
415
|
-
$[$T.BRACKET_R] = createToken({
|
|
416
|
-
name: $T.BRACKET_R,
|
|
417
|
-
pattern: /\]/,
|
|
418
|
-
push_mode: "main",
|
|
419
|
-
categories: [$[$T.ANY]],
|
|
420
|
-
})
|
|
421
|
-
|
|
422
|
-
const quotes = [
|
|
423
|
-
$[$T.QUOTE_SINGLE_START],
|
|
424
|
-
$[$T.QUOTE_DOUBLE_START],
|
|
425
|
-
$[$T.QUOTE_BACKTICK_START],
|
|
426
|
-
]
|
|
427
|
-
|
|
428
|
-
const quotesEnds = [
|
|
429
|
-
$[$T.QUOTE_SINGLE_END],
|
|
430
|
-
$[$T.QUOTE_DOUBLE_END],
|
|
431
|
-
$[$T.QUOTE_BACKTICK_END],
|
|
432
|
-
]
|
|
433
|
-
|
|
434
|
-
/* #regionend */
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
const toBracket = (mode?: string): string => `bracket_${mode!}`
|
|
438
|
-
const lexerOptions = {
|
|
439
|
-
modes: {
|
|
440
|
-
main: [
|
|
441
|
-
$[$T._],
|
|
442
|
-
...parens,
|
|
443
|
-
...(opts.arrayValues ? [$[$T.BRACKET_L]] : []), // moves to bracket_main until a bracket pops it back out
|
|
444
|
-
...operators,
|
|
445
|
-
...quotes, // moves to not*
|
|
446
|
-
...(opts.regexValues ? [$[$T.REGEX_START]] : []), // moves to notRegex
|
|
447
|
-
$[$T.VALUE_UNQUOTED], // moves to maybeQuoteError
|
|
448
|
-
],
|
|
449
|
-
endQuotes: [
|
|
450
|
-
$[$T._],
|
|
451
|
-
...parens,
|
|
452
|
-
...(opts.arrayValues ? [$[$T.BRACKET_L]] : []), // moves to bracket_main until a bracket pops it back out to main
|
|
453
|
-
...operators,
|
|
454
|
-
...quotesEnds,
|
|
455
|
-
$[$T.VALUE_UNQUOTED], // moves to maybeQuoteError
|
|
456
|
-
...(opts.regexValues ? [$[$T.REGEX_START]] : []), // error
|
|
457
|
-
],
|
|
458
|
-
// we can have situations like `a"` where the left quote is missing
|
|
459
|
-
// we want the quote to match a quote end so that it pushes the state to main again, instead of shifting how everything is parsed
|
|
460
|
-
maybeQuoteError: [
|
|
461
|
-
...quotesEnds,
|
|
462
|
-
...(opts.regexValues ? [$[$T.REGEX_END]] : []),
|
|
463
|
-
],
|
|
464
|
-
// all move to endQuotes
|
|
465
|
-
notSingle: [$[$T.VALUE_NOT_SINGLE], $[$T.QUOTE_SINGLE_END]],
|
|
466
|
-
notDouble: [$[$T.VALUE_NOT_DOUBLE], $[$T.QUOTE_DOUBLE_END]],
|
|
467
|
-
notBacktick: [$[$T.VALUE_NOT_BACKTICK], $[$T.QUOTE_BACKTICK_END]],
|
|
468
|
-
...(opts.regexValues
|
|
469
|
-
? {
|
|
470
|
-
notRegex: [
|
|
471
|
-
$[$T.VALUE_REGEX],
|
|
472
|
-
$[$T.REGEX_END], // regex is empty
|
|
473
|
-
], // moves to regexEnd
|
|
474
|
-
regexEnd: [$[$T.REGEX_END]], // moves to main
|
|
475
|
-
} : {}),
|
|
476
|
-
...(opts.arrayValues
|
|
477
|
-
? {
|
|
478
|
-
bracket_main: [
|
|
479
|
-
...changePushMode(quotes, toBracket),
|
|
480
|
-
$[$T.BRACKET_R], // move back to main
|
|
481
|
-
$[$T.BRACKET_VALUE_UNQUOTED],
|
|
482
|
-
],
|
|
483
|
-
// all the following follow the same logic as the non-bracket modes, except operators and parens and regexes are not supported and are just parsed as values with BRACKET_VALUE_UNQUOTED
|
|
484
|
-
// the following tokens are also cloned to push differently: quotes (above), quote values, and quote ends
|
|
485
|
-
// they can still be matched because their parent categories are also cloned and it's those we match against
|
|
486
|
-
bracket_endQuotes: [
|
|
487
|
-
$[$T._],
|
|
488
|
-
...changePushMode(quotesEnds, toBracket),
|
|
489
|
-
$[$T.BRACKET_R], // move back to main
|
|
490
|
-
$[$T.BRACKET_VALUE_UNQUOTED],
|
|
491
|
-
],
|
|
492
|
-
bracket_maybeQuoteError: changePushMode(quotesEnds, toBracket),
|
|
493
|
-
bracket_notSingle: changePushMode([
|
|
494
|
-
$[$T.VALUE_NOT_SINGLE], $[$T.QUOTE_SINGLE_END],
|
|
495
|
-
], toBracket),
|
|
496
|
-
bracket_notDouble: changePushMode([
|
|
497
|
-
$[$T.VALUE_NOT_DOUBLE], $[$T.QUOTE_DOUBLE_END],
|
|
498
|
-
], toBracket),
|
|
499
|
-
bracket_notBacktick: changePushMode([
|
|
500
|
-
$[$T.VALUE_NOT_BACKTICK], $[$T.QUOTE_BACKTICK_END],
|
|
501
|
-
], toBracket),
|
|
502
|
-
} : {}
|
|
503
|
-
),
|
|
504
|
-
|
|
505
|
-
},
|
|
506
|
-
defaultMode: "main",
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
const lexer = new Lexer(lexerOptions) // only because we don't care about newlines
|
|
510
|
-
return { tokens: $, lexer, info: { expandedSepAlsoCustom, customOpAlsoNegation } }
|
|
511
|
-
}
|
|
512
|
-
|
package/src/grammar/index.ts
DELETED
package/src/parser.ts
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The parser's methods are often long and have a lot of documentation per method, so it's methods have been split into mixins. They can be found in the `./methods` folder.
|
|
3
|
-
*
|
|
4
|
-
* Writing from within any of these methods is like writing a method from here except:
|
|
5
|
-
* - `this` calls are wrapped in `(this as any as Parser<T>)`
|
|
6
|
-
* - private method/property access requires `// @ts-expect-error`.
|
|
7
|
-
* - recursion with hidden parameters requires re-typing this (see evaluate/validate for examples) since otherwise if we only retyped the function it would become unbound from `this`.
|
|
8
|
-
*
|
|
9
|
-
* Docs work like normal (on methods). From the outside, users of the library cannot even tell the class is composed of mixins.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type { Mixin } from "@alanscodelog/utils"
|
|
13
|
-
import { isWhitespace, mixin } from "@alanscodelog/utils"
|
|
14
|
-
import { createSyntaxDiagramsCode, type ILexingResult, type Lexer } from "chevrotain"
|
|
15
|
-
|
|
16
|
-
import { token as tokenHandler } from "./ast/handlers.js"
|
|
17
|
-
import { createTokens } from "./grammar/createTokens.js"
|
|
18
|
-
import { ParserBase } from "./grammar/ParserBase.js"
|
|
19
|
-
import { BooleanParserLibraryError } from "./helpers/errors.js"
|
|
20
|
-
import { checkParserOpts } from "./helpers/parser/checkParserOpts.js"
|
|
21
|
-
import { getUnclosedRightParenCount } from "./helpers/parser/getUnclosedRightParenCount.js"
|
|
22
|
-
import { parseParserOptions, seal } from "./helpers/parser/index.js"
|
|
23
|
-
import { AutocompleteMixin } from "./methods/autocomplete.js"
|
|
24
|
-
import { AutoreplaceMixin } from "./methods/autoreplace.js"
|
|
25
|
-
import { Autosuggest } from "./methods/autosuggest.js"
|
|
26
|
-
import { EvaluateMixin } from "./methods/evaluate.js"
|
|
27
|
-
import { GetBestIndexesMixin } from "./methods/getBestIndex.js"
|
|
28
|
-
import { GetIndexMixin } from "./methods/getIndexes.js"
|
|
29
|
-
import { NormalizeMixin, ValidateMixin } from "./methods/index.js"
|
|
30
|
-
import type { ParserResults } from "./types/ast.js"
|
|
31
|
-
import { ERROR_CODES } from "./types/errors.js"
|
|
32
|
-
import type { FullParserOptions, ParserOptions } from "./types/parser.js"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Creates the main parser class which handles all functionality (evaluation, validation, etc).
|
|
37
|
-
*/
|
|
38
|
-
export class Parser<T extends {} = {}> {
|
|
39
|
-
options: FullParserOptions<T>
|
|
40
|
-
|
|
41
|
-
private readonly rawOptions: ParserOptions<T>
|
|
42
|
-
|
|
43
|
-
parser: ParserBase<T>
|
|
44
|
-
|
|
45
|
-
private readonly lexer: Lexer
|
|
46
|
-
|
|
47
|
-
private readonly tokens: ReturnType<typeof createTokens>["tokens"]
|
|
48
|
-
|
|
49
|
-
info: ReturnType<typeof createTokens>["info"]
|
|
50
|
-
|
|
51
|
-
constructor(options?: ParserOptions<T>) {
|
|
52
|
-
this.rawOptions = options ?? {}
|
|
53
|
-
const opts = parseParserOptions<T>(this.rawOptions)
|
|
54
|
-
checkParserOpts<T>(opts)
|
|
55
|
-
this.options = opts
|
|
56
|
-
const { lexer, tokens, info } = createTokens<T>(opts)
|
|
57
|
-
this.lexer = lexer
|
|
58
|
-
this.tokens = tokens
|
|
59
|
-
this.info = info
|
|
60
|
-
this.parser = new ParserBase<T>(opts, this.tokens, this.info)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Parses a string.
|
|
65
|
-
*/
|
|
66
|
-
parse(input: string): ParserResults {
|
|
67
|
-
if (isWhitespace(input)) {
|
|
68
|
-
return tokenHandler.value(undefined, { start: 0, end: 0 }) as any
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
let lexed = this._lex(input)
|
|
72
|
-
|
|
73
|
-
const shift = getUnclosedRightParenCount(lexed.tokens, this.tokens)
|
|
74
|
-
if (shift) {
|
|
75
|
-
input = "(".repeat(shift) + input
|
|
76
|
-
lexed = this._lex(input)
|
|
77
|
-
}
|
|
78
|
-
this.parser.shift = shift
|
|
79
|
-
this.parser.input = lexed.tokens
|
|
80
|
-
this.parser.rawInput = input
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* The parser can't handle unmatched right parens (i.e. left is missing) so we just insert them and shift the locations of all the tokens. Then the parser is designed to ignore parenthesis we added at the start and just return undefined for that rule as if the parenthesis didn't exist.
|
|
84
|
-
*/
|
|
85
|
-
try {
|
|
86
|
-
if (lexed.errors.length > 0) throw new Error("Unexpected Lexer Errors")
|
|
87
|
-
this.parser.input = lexed.tokens
|
|
88
|
-
const res = this.parser.main()
|
|
89
|
-
if (res === undefined) { throw new Error("throw") }
|
|
90
|
-
// hidden param
|
|
91
|
-
// eslint-disable-next-line prefer-rest-params
|
|
92
|
-
if (!arguments[1]?.unsealed) seal(res)
|
|
93
|
-
return res
|
|
94
|
-
} catch (error: unknown) {
|
|
95
|
-
// eslint-disable-next-line no-ex-assign
|
|
96
|
-
if ((error as Error).message === "throw") error = undefined
|
|
97
|
-
const err = new BooleanParserLibraryError(ERROR_CODES.PARSER_ERROR, {
|
|
98
|
-
input,
|
|
99
|
-
options: this.rawOptions,
|
|
100
|
-
"parsed options": this.options,
|
|
101
|
-
error: error as Error,
|
|
102
|
-
"lexed tokens": lexed.tokens,
|
|
103
|
-
"lexer errors": lexed.errors,
|
|
104
|
-
"parser errors": this.parser.errors,
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
throw err
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// needed for evaluate and validate so they are only checked on demand
|
|
112
|
-
private evaluationOptionsChecked: boolean = false
|
|
113
|
-
|
|
114
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
115
|
-
_checkEvaluationOptions(): void {
|
|
116
|
-
if (!this.evaluationOptionsChecked) {
|
|
117
|
-
checkParserOpts(this.options, true)
|
|
118
|
-
this.evaluationOptionsChecked = true
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
private validationOptionsChecked: boolean = false
|
|
123
|
-
|
|
124
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
125
|
-
_checkValidationOptions(): void {
|
|
126
|
-
if (!this.validationOptionsChecked) {
|
|
127
|
-
checkParserOpts(this.options, false, true)
|
|
128
|
-
this.validationOptionsChecked = true
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Generates a railroad diagram for debugging. Does not 100% represent how things are actually handled internally.
|
|
134
|
-
*
|
|
135
|
-
* Not exposed because it uses the raw chevrotain tokens.
|
|
136
|
-
*
|
|
137
|
-
* **Note: It is not 100% accurate. Some special cases are parsed one way but handled internally differently.**
|
|
138
|
-
*/
|
|
139
|
-
private _generateRailRoadDiagram(): string {
|
|
140
|
-
const serialized = this.parser.getSerializedGastProductions()
|
|
141
|
-
const html = createSyntaxDiagramsCode(serialized)
|
|
142
|
-
return html
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* For debugging.
|
|
147
|
-
* Not exposed because it returns the raw chevrotain tokens.
|
|
148
|
-
*/
|
|
149
|
-
private _lex(input: string): ILexingResult {
|
|
150
|
-
return this.lexer.tokenize(input)
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export interface Parser<T extends {} = {}> extends Mixin<
|
|
155
|
-
| AutocompleteMixin<T>
|
|
156
|
-
| AutoreplaceMixin
|
|
157
|
-
| Autosuggest<T>
|
|
158
|
-
| EvaluateMixin<T>
|
|
159
|
-
| ValidateMixin<T>
|
|
160
|
-
| NormalizeMixin<T>
|
|
161
|
-
| GetIndexMixin<T>
|
|
162
|
-
| GetBestIndexesMixin
|
|
163
|
-
>,
|
|
164
|
-
AutocompleteMixin<T>,
|
|
165
|
-
AutoreplaceMixin,
|
|
166
|
-
Autosuggest<T>,
|
|
167
|
-
EvaluateMixin<T>,
|
|
168
|
-
ValidateMixin < T >,
|
|
169
|
-
NormalizeMixin<T>,
|
|
170
|
-
GetIndexMixin<T>,
|
|
171
|
-
GetBestIndexesMixin
|
|
172
|
-
{}
|
|
173
|
-
|
|
174
|
-
mixin(Parser, [
|
|
175
|
-
AutocompleteMixin,
|
|
176
|
-
AutoreplaceMixin,
|
|
177
|
-
Autosuggest,
|
|
178
|
-
EvaluateMixin,
|
|
179
|
-
ValidateMixin,
|
|
180
|
-
NormalizeMixin,
|
|
181
|
-
GetIndexMixin,
|
|
182
|
-
GetBestIndexesMixin,
|
|
183
|
-
])
|