@witchcraft/expressit 0.0.2
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 +86 -0
- package/dist/ast/builders/array.d.ts +8 -0
- package/dist/ast/builders/array.d.ts.map +1 -0
- package/dist/ast/builders/array.js +31 -0
- package/dist/ast/builders/condition.d.ts +20 -0
- package/dist/ast/builders/condition.d.ts.map +1 -0
- package/dist/ast/builders/condition.js +28 -0
- package/dist/ast/builders/delim.d.ts +11 -0
- package/dist/ast/builders/delim.d.ts.map +1 -0
- package/dist/ast/builders/delim.js +20 -0
- package/dist/ast/builders/error.d.ts +9 -0
- package/dist/ast/builders/error.d.ts.map +1 -0
- package/dist/ast/builders/error.js +16 -0
- package/dist/ast/builders/expression.d.ts +12 -0
- package/dist/ast/builders/expression.d.ts.map +1 -0
- package/dist/ast/builders/expression.js +31 -0
- package/dist/ast/builders/group.d.ts +20 -0
- package/dist/ast/builders/group.d.ts.map +1 -0
- package/dist/ast/builders/group.js +47 -0
- package/dist/ast/builders/index.d.ts +12 -0
- package/dist/ast/builders/index.d.ts.map +1 -0
- package/dist/ast/builders/index.js +24 -0
- package/dist/ast/builders/isFullPos.d.ts +6 -0
- package/dist/ast/builders/isFullPos.d.ts.map +1 -0
- package/dist/ast/builders/isFullPos.js +6 -0
- package/dist/ast/builders/pos.d.ts +21 -0
- package/dist/ast/builders/pos.d.ts.map +1 -0
- package/dist/ast/builders/pos.js +28 -0
- package/dist/ast/builders/token.d.ts +12 -0
- package/dist/ast/builders/token.d.ts.map +1 -0
- package/dist/ast/builders/token.js +26 -0
- package/dist/ast/builders/type.d.ts +6 -0
- package/dist/ast/builders/type.d.ts.map +1 -0
- package/dist/ast/builders/type.js +37 -0
- package/dist/ast/builders/variable.d.ts +17 -0
- package/dist/ast/builders/variable.d.ts.map +1 -0
- package/dist/ast/builders/variable.js +62 -0
- package/dist/ast/classes/ArrayNode.d.ts +18 -0
- package/dist/ast/classes/ArrayNode.d.ts.map +1 -0
- package/dist/ast/classes/ArrayNode.js +55 -0
- package/dist/ast/classes/Condition.d.ts +13 -0
- package/dist/ast/classes/Condition.d.ts.map +1 -0
- package/dist/ast/classes/Condition.js +21 -0
- package/dist/ast/classes/ConditionNode.d.ts +73 -0
- package/dist/ast/classes/ConditionNode.d.ts.map +1 -0
- package/dist/ast/classes/ConditionNode.js +101 -0
- package/dist/ast/classes/ErrorToken.d.ts +27 -0
- package/dist/ast/classes/ErrorToken.d.ts.map +1 -0
- package/dist/ast/classes/ErrorToken.js +47 -0
- package/dist/ast/classes/Expression.d.ts +13 -0
- package/dist/ast/classes/Expression.d.ts.map +1 -0
- package/dist/ast/classes/Expression.js +19 -0
- package/dist/ast/classes/ExpressionNode.d.ts +21 -0
- package/dist/ast/classes/ExpressionNode.d.ts.map +1 -0
- package/dist/ast/classes/ExpressionNode.js +57 -0
- package/dist/ast/classes/GroupNode.d.ts +64 -0
- package/dist/ast/classes/GroupNode.d.ts.map +1 -0
- package/dist/ast/classes/GroupNode.js +69 -0
- package/dist/ast/classes/Node.d.ts +22 -0
- package/dist/ast/classes/Node.d.ts.map +1 -0
- package/dist/ast/classes/Node.js +28 -0
- package/dist/ast/classes/Token.d.ts +27 -0
- package/dist/ast/classes/Token.d.ts.map +1 -0
- package/dist/ast/classes/Token.js +28 -0
- package/dist/ast/classes/ValidToken.d.ts +26 -0
- package/dist/ast/classes/ValidToken.d.ts.map +1 -0
- package/dist/ast/classes/ValidToken.js +49 -0
- package/dist/ast/classes/VariableNode.d.ts +33 -0
- package/dist/ast/classes/VariableNode.d.ts.map +1 -0
- package/dist/ast/classes/VariableNode.js +58 -0
- package/dist/ast/classes/index.d.ts +12 -0
- package/dist/ast/classes/index.d.ts.map +1 -0
- package/dist/ast/classes/index.js +24 -0
- package/dist/ast/handlers.d.ts +42 -0
- package/dist/ast/handlers.d.ts.map +1 -0
- package/dist/ast/handlers.js +150 -0
- package/dist/ast/index.d.ts +4 -0
- package/dist/ast/index.d.ts.map +1 -0
- package/dist/ast/index.js +8 -0
- package/dist/examples/advancedValueComparer.d.ts +3 -0
- package/dist/examples/advancedValueComparer.d.ts.map +1 -0
- package/dist/examples/advancedValueComparer.js +28 -0
- package/dist/examples/shortcutContextParser.d.ts +22 -0
- package/dist/examples/shortcutContextParser.d.ts.map +1 -0
- package/dist/examples/shortcutContextParser.js +126 -0
- package/dist/global.d.js +1 -0
- package/dist/grammar/ParserBase.d.ts +51 -0
- package/dist/grammar/ParserBase.d.ts.map +1 -0
- package/dist/grammar/ParserBase.js +516 -0
- package/dist/grammar/createTokens.d.ts +56 -0
- package/dist/grammar/createTokens.d.ts.map +1 -0
- package/dist/grammar/createTokens.js +843 -0
- package/dist/grammar/index.d.ts +3 -0
- package/dist/grammar/index.d.ts.map +1 -0
- package/dist/grammar/index.js +6 -0
- package/dist/helpers/errors.d.ts +9 -0
- package/dist/helpers/errors.d.ts.map +1 -0
- package/dist/helpers/errors.js +41 -0
- package/dist/helpers/general/applyBoolean.d.ts +3 -0
- package/dist/helpers/general/applyBoolean.d.ts.map +1 -0
- package/dist/helpers/general/applyBoolean.js +17 -0
- package/dist/helpers/general/applyPrefix.d.ts +4 -0
- package/dist/helpers/general/applyPrefix.d.ts.map +1 -0
- package/dist/helpers/general/applyPrefix.js +9 -0
- package/dist/helpers/general/defaultConditionNormalizer.d.ts +3 -0
- package/dist/helpers/general/defaultConditionNormalizer.d.ts.map +1 -0
- package/dist/helpers/general/defaultConditionNormalizer.js +6 -0
- package/dist/helpers/general/defaultKeyParser.d.ts +3 -0
- package/dist/helpers/general/defaultKeyParser.d.ts.map +1 -0
- package/dist/helpers/general/defaultKeyParser.js +8 -0
- package/dist/helpers/general/defaultPrefixApplier.d.ts +3 -0
- package/dist/helpers/general/defaultPrefixApplier.d.ts.map +1 -0
- package/dist/helpers/general/defaultPrefixApplier.js +6 -0
- package/dist/helpers/general/defaultValueComparer.d.ts +3 -0
- package/dist/helpers/general/defaultValueComparer.d.ts.map +1 -0
- package/dist/helpers/general/defaultValueComparer.js +6 -0
- package/dist/helpers/general/index.d.ts +7 -0
- package/dist/helpers/general/index.d.ts.map +1 -0
- package/dist/helpers/general/index.js +14 -0
- package/dist/helpers/index.d.ts +4 -0
- package/dist/helpers/index.d.ts.map +1 -0
- package/dist/helpers/index.js +8 -0
- package/dist/helpers/parser/assignParents.d.ts +4 -0
- package/dist/helpers/parser/assignParents.d.ts.map +1 -0
- package/dist/helpers/parser/assignParents.js +71 -0
- package/dist/helpers/parser/checkParserOpts.d.ts +3 -0
- package/dist/helpers/parser/checkParserOpts.d.ts.map +1 -0
- package/dist/helpers/parser/checkParserOpts.js +126 -0
- package/dist/helpers/parser/extractPosition.d.ts +9 -0
- package/dist/helpers/parser/extractPosition.d.ts.map +1 -0
- package/dist/helpers/parser/extractPosition.js +9 -0
- package/dist/helpers/parser/getUnclosedRightParenCount.d.ts +5 -0
- package/dist/helpers/parser/getUnclosedRightParenCount.d.ts.map +1 -0
- package/dist/helpers/parser/getUnclosedRightParenCount.js +20 -0
- package/dist/helpers/parser/index.d.ts +9 -0
- package/dist/helpers/parser/index.d.ts.map +1 -0
- package/dist/helpers/parser/index.js +18 -0
- package/dist/helpers/parser/parseParserOptions.d.ts +4 -0
- package/dist/helpers/parser/parseParserOptions.d.ts.map +1 -0
- package/dist/helpers/parser/parseParserOptions.js +45 -0
- package/dist/helpers/parser/seal.d.ts +8 -0
- package/dist/helpers/parser/seal.d.ts.map +1 -0
- package/dist/helpers/parser/seal.js +10 -0
- package/dist/helpers/parser/setParent.d.ts +6 -0
- package/dist/helpers/parser/setParent.d.ts.map +1 -0
- package/dist/helpers/parser/setParent.js +4 -0
- package/dist/helpers/parser/unescape.d.ts +3 -0
- package/dist/helpers/parser/unescape.d.ts.map +1 -0
- package/dist/helpers/parser/unescape.js +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/methods/autocomplete.d.ts +18 -0
- package/dist/methods/autocomplete.d.ts.map +1 -0
- package/dist/methods/autocomplete.js +109 -0
- package/dist/methods/autoreplace.d.ts +13 -0
- package/dist/methods/autoreplace.d.ts.map +1 -0
- package/dist/methods/autoreplace.js +36 -0
- package/dist/methods/autosuggest.d.ts +28 -0
- package/dist/methods/autosuggest.d.ts.map +1 -0
- package/dist/methods/autosuggest.js +371 -0
- package/dist/methods/evaluate.d.ts +11 -0
- package/dist/methods/evaluate.d.ts.map +1 -0
- package/dist/methods/evaluate.js +30 -0
- package/dist/methods/getBestIndex.d.ts +19 -0
- package/dist/methods/getBestIndex.d.ts.map +1 -0
- package/dist/methods/getBestIndex.js +53 -0
- package/dist/methods/getIndexes.d.ts +17 -0
- package/dist/methods/getIndexes.d.ts.map +1 -0
- package/dist/methods/getIndexes.js +97 -0
- package/dist/methods/index.d.ts +9 -0
- package/dist/methods/index.d.ts.map +1 -0
- package/dist/methods/index.js +18 -0
- package/dist/methods/normalize.d.ts +12 -0
- package/dist/methods/normalize.d.ts.map +1 -0
- package/dist/methods/normalize.js +99 -0
- package/dist/methods/validate.d.ts +11 -0
- package/dist/methods/validate.d.ts.map +1 -0
- package/dist/methods/validate.js +111 -0
- package/dist/package.js +7 -0
- package/dist/package.json.js +193 -0
- package/dist/parser.d.ts +58 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +136 -0
- package/dist/types/ast.d.ts +70 -0
- package/dist/types/ast.d.ts.map +1 -0
- package/dist/types/ast.js +29 -0
- package/dist/types/autocomplete.d.ts +143 -0
- package/dist/types/autocomplete.d.ts.map +1 -0
- package/dist/types/autocomplete.js +24 -0
- package/dist/types/errors.d.ts +34 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +10 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +9 -0
- package/dist/types/parser.d.ts +451 -0
- package/dist/types/parser.d.ts.map +1 -0
- package/dist/types/parser.js +1 -0
- package/dist/utils/extractTokens.d.ts +8 -0
- package/dist/utils/extractTokens.d.ts.map +1 -0
- package/dist/utils/extractTokens.js +50 -0
- package/dist/utils/getCursorInfo.d.ts +7 -0
- package/dist/utils/getCursorInfo.d.ts.map +1 -0
- package/dist/utils/getCursorInfo.js +86 -0
- package/dist/utils/getOppositeDelimiter.d.ts +6 -0
- package/dist/utils/getOppositeDelimiter.d.ts.map +1 -0
- package/dist/utils/getOppositeDelimiter.js +35 -0
- package/dist/utils/getSurroundingErrors.d.ts +25 -0
- package/dist/utils/getSurroundingErrors.d.ts.map +1 -0
- package/dist/utils/getSurroundingErrors.js +37 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +20 -0
- package/dist/utils/isBracket.d.ts +3 -0
- package/dist/utils/isBracket.d.ts.map +1 -0
- package/dist/utils/isBracket.js +7 -0
- package/dist/utils/isDelimiter.d.ts +6 -0
- package/dist/utils/isDelimiter.d.ts.map +1 -0
- package/dist/utils/isDelimiter.js +17 -0
- package/dist/utils/isParen.d.ts +3 -0
- package/dist/utils/isParen.d.ts.map +1 -0
- package/dist/utils/isParen.js +7 -0
- package/dist/utils/isQuote.d.ts +4 -0
- package/dist/utils/isQuote.d.ts.map +1 -0
- package/dist/utils/isQuote.js +7 -0
- package/dist/utils/prettyAst.d.ts +35 -0
- package/dist/utils/prettyAst.d.ts.map +1 -0
- package/dist/utils/prettyAst.js +112 -0
- package/package.json +152 -0
- package/src/ast/builders/array.ts +45 -0
- package/src/ast/builders/condition.ts +56 -0
- package/src/ast/builders/delim.ts +39 -0
- package/src/ast/builders/error.ts +22 -0
- package/src/ast/builders/expression.ts +66 -0
- package/src/ast/builders/group.ts +79 -0
- package/src/ast/builders/index.ts +13 -0
- package/src/ast/builders/isFullPos.ts +10 -0
- package/src/ast/builders/pos.ts +57 -0
- package/src/ast/builders/token.ts +46 -0
- package/src/ast/builders/type.ts +32 -0
- package/src/ast/builders/variable.ts +89 -0
- package/src/ast/classes/ArrayNode.ts +46 -0
- package/src/ast/classes/Condition.ts +22 -0
- package/src/ast/classes/ConditionNode.ts +141 -0
- package/src/ast/classes/ErrorToken.ts +49 -0
- package/src/ast/classes/Expression.ts +26 -0
- package/src/ast/classes/ExpressionNode.ts +62 -0
- package/src/ast/classes/GroupNode.ts +127 -0
- package/src/ast/classes/Node.ts +47 -0
- package/src/ast/classes/Token.ts +59 -0
- package/src/ast/classes/ValidToken.ts +56 -0
- package/src/ast/classes/VariableNode.ts +67 -0
- package/src/ast/classes/index.ts +13 -0
- package/src/ast/handlers.ts +190 -0
- package/src/ast/index.ts +5 -0
- package/src/examples/advancedValueComparer.ts +31 -0
- package/src/examples/shortcutContextParser.ts +140 -0
- package/src/global.d.ts +4 -0
- package/src/grammar/ParserBase.ts +715 -0
- package/src/grammar/createTokens.ts +512 -0
- package/src/grammar/index.ts +4 -0
- package/src/helpers/errors.ts +45 -0
- package/src/helpers/general/applyBoolean.ts +9 -0
- package/src/helpers/general/applyPrefix.ts +7 -0
- package/src/helpers/general/defaultConditionNormalizer.ts +9 -0
- package/src/helpers/general/defaultKeyParser.ts +8 -0
- package/src/helpers/general/defaultPrefixApplier.ts +7 -0
- package/src/helpers/general/defaultValueComparer.ts +7 -0
- package/src/helpers/general/index.ts +8 -0
- package/src/helpers/index.ts +5 -0
- package/src/helpers/parser/assignParents.ts +51 -0
- package/src/helpers/parser/checkParserOpts.ts +143 -0
- package/src/helpers/parser/extractPosition.ts +15 -0
- package/src/helpers/parser/getUnclosedRightParenCount.ts +22 -0
- package/src/helpers/parser/index.ts +10 -0
- package/src/helpers/parser/parseParserOptions.ts +54 -0
- package/src/helpers/parser/seal.ts +14 -0
- package/src/helpers/parser/setParent.ts +5 -0
- package/src/helpers/parser/unescape.ts +4 -0
- package/src/index.ts +7 -0
- package/src/methods/autocomplete.ts +128 -0
- package/src/methods/autoreplace.ts +46 -0
- package/src/methods/autosuggest.ts +543 -0
- package/src/methods/evaluate.ts +37 -0
- package/src/methods/getBestIndex.ts +53 -0
- package/src/methods/getIndexes.ts +99 -0
- package/src/methods/index.ts +10 -0
- package/src/methods/normalize.ts +138 -0
- package/src/methods/validate.ts +141 -0
- package/src/package.js +11 -0
- package/src/parser.ts +183 -0
- package/src/types/ast.ts +148 -0
- package/src/types/autocomplete.ts +152 -0
- package/src/types/errors.ts +40 -0
- package/src/types/index.ts +6 -0
- package/src/types/parser.ts +479 -0
- package/src/utils/extractTokens.ts +67 -0
- package/src/utils/getCursorInfo.ts +106 -0
- package/src/utils/getOppositeDelimiter.ts +36 -0
- package/src/utils/getSurroundingErrors.ts +57 -0
- package/src/utils/index.ts +11 -0
- package/src/utils/isBracket.ts +6 -0
- package/src/utils/isDelimiter.ts +18 -0
- package/src/utils/isParen.ts +6 -0
- package/src/utils/isQuote.ts +6 -0
- package/src/utils/prettyAst.ts +152 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-shadow */
|
|
2
|
+
|
|
3
|
+
import { ArrayNode } from "./classes/ArrayNode.js"
|
|
4
|
+
import { ConditionNode } from "./classes/ConditionNode.js"
|
|
5
|
+
import { ErrorToken } from "./classes/ErrorToken.js"
|
|
6
|
+
import { ExpressionNode } from "./classes/ExpressionNode.js"
|
|
7
|
+
import { GroupNode } from "./classes/GroupNode.js"
|
|
8
|
+
import { ValidToken } from "./classes/ValidToken.js"
|
|
9
|
+
import { VariableNode } from "./classes/VariableNode.js"
|
|
10
|
+
|
|
11
|
+
import { type AnyToken, type FirstConstructorParam, type Position, TOKEN_TYPE, type TokenBooleanTypes, type TokenDelimiterTypes, type TokenOperatorTypes, type TokenQuoteTypes } from "../types/ast.js"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/* #region HELPERS */
|
|
15
|
+
function error<T extends TOKEN_TYPE>(pos: number, expected: T[]): ErrorToken<T> {
|
|
16
|
+
if (pos === undefined) throw new Error("should never happen, passed undefined position for error token")
|
|
17
|
+
return new ErrorToken({ expected, start: pos, end: pos })
|
|
18
|
+
}
|
|
19
|
+
/* #regionend */
|
|
20
|
+
|
|
21
|
+
/* #region TOKENS */
|
|
22
|
+
const operators = <T extends TokenOperatorTypes>
|
|
23
|
+
(type: T) =>
|
|
24
|
+
(value: string, pos: Position): ValidToken<T> => new ValidToken({ value, type, ...pos })
|
|
25
|
+
|
|
26
|
+
const delimiters = <T extends TokenDelimiterTypes>
|
|
27
|
+
(type: T) =>
|
|
28
|
+
(value: string | undefined, pos: Position): ValidToken<T> | undefined =>
|
|
29
|
+
// check must be falsy, we want to return undefined when given ""
|
|
30
|
+
value ? new ValidToken({ value, type, ...pos }) : undefined
|
|
31
|
+
|
|
32
|
+
const maybeToken = <T extends TOKEN_TYPE>(type: T) => (value: string | undefined, pos: Position,): AnyToken<T> => {
|
|
33
|
+
if (value === undefined) {
|
|
34
|
+
return error(pos.end, [type])
|
|
35
|
+
} else {
|
|
36
|
+
return new ValidToken({ value, type, ...pos })
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const token = {
|
|
41
|
+
value: maybeToken(TOKEN_TYPE.VALUE),
|
|
42
|
+
custom: maybeToken(TOKEN_TYPE.OP_CUSTOM),
|
|
43
|
+
sep: maybeToken(TOKEN_TYPE.OP_EXPANDED_SEP),
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** We want to handle all the types outside the grammar file. This makes it easier without trying to check the value. */
|
|
47
|
+
export const delimiter = {
|
|
48
|
+
parenL: delimiters(TOKEN_TYPE.PARENL),
|
|
49
|
+
parenR: delimiters(TOKEN_TYPE.PARENR),
|
|
50
|
+
bracketL: delimiters(TOKEN_TYPE.BRACKETL),
|
|
51
|
+
bracketR: delimiters(TOKEN_TYPE.BRACKETR),
|
|
52
|
+
double: delimiters(TOKEN_TYPE.DOUBLEQUOTE),
|
|
53
|
+
single: delimiters(TOKEN_TYPE.SINGLEQUOTE),
|
|
54
|
+
regex: delimiters(TOKEN_TYPE.REGEX),
|
|
55
|
+
tick: delimiters(TOKEN_TYPE.BACKTICK),
|
|
56
|
+
tokenError: error,
|
|
57
|
+
}
|
|
58
|
+
export const operator = {
|
|
59
|
+
and: operators(TOKEN_TYPE.AND),
|
|
60
|
+
or: operators(TOKEN_TYPE.OR),
|
|
61
|
+
not: operators(TOKEN_TYPE.NOT),
|
|
62
|
+
}
|
|
63
|
+
/* #regionend */
|
|
64
|
+
|
|
65
|
+
/* #region AST NODES */
|
|
66
|
+
export function variable(
|
|
67
|
+
prefix: ValidToken<TOKEN_TYPE.VALUE> | null | undefined,
|
|
68
|
+
quoteL: AnyToken<TokenQuoteTypes> | null | undefined,
|
|
69
|
+
value: AnyToken<TOKEN_TYPE.VALUE> | null | undefined,
|
|
70
|
+
quoteR: AnyToken<TokenQuoteTypes> | null | undefined,
|
|
71
|
+
flags?: ValidToken<TOKEN_TYPE.VALUE>
|
|
72
|
+
): VariableNode {
|
|
73
|
+
const node: FirstConstructorParam<typeof VariableNode> = {
|
|
74
|
+
prefix: prefix ?? undefined,
|
|
75
|
+
value: value ?? error((prefix?.end ?? quoteL?.end ?? quoteR?.start)!, [TOKEN_TYPE.VALUE]),
|
|
76
|
+
start: (prefix?.start ?? quoteL?.start ?? value?.start ?? quoteR?.start)!,
|
|
77
|
+
end: (quoteR?.end ?? value?.end ?? quoteL?.end ?? prefix?.end)!,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (quoteL || quoteR) {
|
|
81
|
+
node.quote = {
|
|
82
|
+
left: quoteL ?? error(node.value.start, [(quoteR!.type)]),
|
|
83
|
+
right: quoteR ?? error(node.value.end, [(quoteL!.type)]),
|
|
84
|
+
}
|
|
85
|
+
if (flags) {
|
|
86
|
+
node.quote.flags = flags
|
|
87
|
+
node.end = node.quote?.flags.end
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const instance = new VariableNode(node as any)
|
|
92
|
+
return instance
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
export function condition(
|
|
97
|
+
not: ValidToken<TOKEN_TYPE.NOT> | null | undefined,
|
|
98
|
+
property: VariableNode | null | undefined,
|
|
99
|
+
{ propertyOperator, sepL, sepR }: {
|
|
100
|
+
propertyOperator?: ConditionNode["propertyOperator"] | null
|
|
101
|
+
sepL?: ValidToken<TOKEN_TYPE.OP_EXPANDED_SEP> | null
|
|
102
|
+
sepR?: ValidToken<TOKEN_TYPE.OP_EXPANDED_SEP> | null
|
|
103
|
+
} = {},
|
|
104
|
+
value?: VariableNode | GroupNode | ArrayNode | null,
|
|
105
|
+
): ConditionNode {
|
|
106
|
+
const start = (not?.start ?? property?.start ?? sepL?.start ?? propertyOperator?.start ?? sepR?.start ?? value?.start)!
|
|
107
|
+
const end = (value?.end ?? sepR?.end ?? propertyOperator?.end ?? sepL?.end ?? property?.end ?? not?.end)!
|
|
108
|
+
const node: FirstConstructorParam<typeof ConditionNode> = {
|
|
109
|
+
value: value ? value : error(end, [TOKEN_TYPE.VALUE]),
|
|
110
|
+
start,
|
|
111
|
+
end,
|
|
112
|
+
}
|
|
113
|
+
if (not) { node.operator = not }
|
|
114
|
+
if (property) node.property = property
|
|
115
|
+
if (propertyOperator) node.propertyOperator = propertyOperator
|
|
116
|
+
if (sepL || sepR) {
|
|
117
|
+
node.sep = {}
|
|
118
|
+
if (sepL) {
|
|
119
|
+
node.sep.left = sepL
|
|
120
|
+
node.property ||= error(sepL.start, [TOKEN_TYPE.VALUE])
|
|
121
|
+
node.propertyOperator ||= error(sepL?.end ?? sepR?.start, [TOKEN_TYPE.VALUE])
|
|
122
|
+
}
|
|
123
|
+
if (sepR) node.sep.right = sepR
|
|
124
|
+
else if (!node.value || node.value instanceof VariableNode) {
|
|
125
|
+
node.sep.right = error(node.value?.start ?? end, [TOKEN_TYPE.OP_EXPANDED_SEP])
|
|
126
|
+
}
|
|
127
|
+
} else if (propertyOperator) {
|
|
128
|
+
node.property ||= error(propertyOperator.start, [TOKEN_TYPE.VALUE])
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const instance = new ConditionNode(node as any)
|
|
132
|
+
return instance
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function expression(
|
|
136
|
+
left: ConditionNode | GroupNode | null | undefined,
|
|
137
|
+
operator: ValidToken<TokenBooleanTypes> | null | undefined,
|
|
138
|
+
right: ConditionNode | GroupNode | null | undefined,
|
|
139
|
+
): ExpressionNode {
|
|
140
|
+
const instance = new ExpressionNode({
|
|
141
|
+
left: left ?? error((operator?.start ?? right?.start)!, [TOKEN_TYPE.VALUE]),
|
|
142
|
+
operator: operator ?? error((left?.end ?? right?.start)!, [TOKEN_TYPE.AND, TOKEN_TYPE.OR]),
|
|
143
|
+
right: right ?? error((operator?.end ?? left?.end)!, [TOKEN_TYPE.VALUE]),
|
|
144
|
+
start: (left?.start ?? operator?.start ?? right?.start)!,
|
|
145
|
+
end: (right?.end ?? operator?.end ?? left?.end)!,
|
|
146
|
+
})
|
|
147
|
+
return instance
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function group(
|
|
151
|
+
operator: ValidToken<TOKEN_TYPE.NOT> | null | undefined,
|
|
152
|
+
prefix: ConditionNode | null | undefined,
|
|
153
|
+
parenL: ValidToken<TOKEN_TYPE.PARENL> | null | undefined,
|
|
154
|
+
condition: GroupNode["expression"],
|
|
155
|
+
parenR: ValidToken<TOKEN_TYPE.PARENR> | null | undefined
|
|
156
|
+
): GroupNode {
|
|
157
|
+
const node: FirstConstructorParam<typeof GroupNode> = {
|
|
158
|
+
prefix: prefix ?? operator ?? undefined,
|
|
159
|
+
expression: condition ?? error((parenL?.end ?? parenR?.start)!, [TOKEN_TYPE.VALUE]),
|
|
160
|
+
paren: {
|
|
161
|
+
left: parenL ?? error((prefix?.end ?? operator?.end ?? condition?.start ?? parenR?.start)!, [TOKEN_TYPE.PARENL]),
|
|
162
|
+
right: parenR ?? error((condition?.end ?? parenL?.end)!, [TOKEN_TYPE.PARENR]),
|
|
163
|
+
},
|
|
164
|
+
start: (prefix?.start ?? operator?.start ?? parenL?.start ?? condition?.start ?? parenR?.start)!,
|
|
165
|
+
end: (parenR?.end ?? condition?.end ?? parenL?.end ?? operator?.end ?? prefix?.end)!,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const instance = new GroupNode(node as any)
|
|
169
|
+
return instance
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function array(
|
|
173
|
+
bracketL: ValidToken<TOKEN_TYPE.BRACKETL>,
|
|
174
|
+
values: VariableNode[],
|
|
175
|
+
bracketR: ValidToken<TOKEN_TYPE.BRACKETR> | null | undefined
|
|
176
|
+
): ArrayNode {
|
|
177
|
+
const node: FirstConstructorParam<typeof ArrayNode> = {
|
|
178
|
+
values,
|
|
179
|
+
bracket: {
|
|
180
|
+
left: bracketL, // always valid for now
|
|
181
|
+
right: bracketR ?? error((values[values.length - 1]?.end ?? bracketL?.end)!, [TOKEN_TYPE.BRACKETR]),
|
|
182
|
+
},
|
|
183
|
+
start: bracketL.start,
|
|
184
|
+
end: (bracketR?.end ?? values[values.length - 1]?.end ?? bracketL.end)!,
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const instance = new ArrayNode(node as any)
|
|
188
|
+
return instance
|
|
189
|
+
}
|
|
190
|
+
/* #regionend */
|
package/src/ast/index.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ValueQuery } from "../types/parser.js"
|
|
2
|
+
|
|
3
|
+
/* TODO TOUPDATE */
|
|
4
|
+
type Operators = ">" | "contains"
|
|
5
|
+
type Prefixes = "num"
|
|
6
|
+
export function valueComparer(contextValue: string, { operator, prefix, value, isRegex, regexFlags }: ValueQuery): boolean {
|
|
7
|
+
let finalValue: any = value
|
|
8
|
+
if (prefix) {
|
|
9
|
+
const val = value as string // it's always a string if prefixed
|
|
10
|
+
switch (prefix as Prefixes) {
|
|
11
|
+
case "num": finalValue = parseInt(val, 2); break
|
|
12
|
+
// ...
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (isRegex) {
|
|
16
|
+
const val = value as string // it's always a string and never prefixed if it's a regex
|
|
17
|
+
const regex = new RegExp(val, regexFlags)
|
|
18
|
+
return contextValue.match(regex) !== null
|
|
19
|
+
}
|
|
20
|
+
if (operator) {
|
|
21
|
+
switch (operator as Operators) {
|
|
22
|
+
// custom operators
|
|
23
|
+
case ">": return contextValue > finalValue
|
|
24
|
+
// ...
|
|
25
|
+
// custom expanded operators
|
|
26
|
+
case "contains": return contextValue.includes(finalValue)
|
|
27
|
+
// ...
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return contextValue === finalValue
|
|
31
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/* TODO TOUPDATE */
|
|
2
|
+
/**
|
|
3
|
+
* A pre-configured parser for parsing shortcut contexts (similar to VSCode's [when clause contexts](https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts)).
|
|
4
|
+
*
|
|
5
|
+
* The only difference is that it does not have a regex operator since you can just do `prop == /regex/`, and because of how it has `prefixableGroups` turned on and how the parser allows groups as values, user's can use shorter queries.
|
|
6
|
+
*
|
|
7
|
+
* It also automatically implements a prefixApplier (variables are joined with `.`) and a value validator (which is why it requires a dummy context and a list of valid regex flags be passed). The value of the dummy context should be true to indicate the key is regexable, otherwise just false or a nested object. Any nested keys found are joined with a `.` and added to a list of valid keys. The prefixApplier is loose and allows things like `a.(b.(c))` and `a(b(c))` to both be parsed as `a.b.c`.
|
|
8
|
+
*
|
|
9
|
+
* The validate function will return a list of positions with a list of errors which includes handling invalid or duplicate regex flags.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { Parser } from "../parser.js"
|
|
13
|
+
import type { Position } from "../types/ast.js"
|
|
14
|
+
import type { ValueQuery } from "../types/parser.js"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
export class ShortcutContextParser<T extends
|
|
18
|
+
Position & { type: ("invalidKey" | "unregexableKey" | "invalidRegexFlag" | "duplicateRegexFlag") } =
|
|
19
|
+
Position & { type: ("invalidKey" | "unregexableKey" | "invalidRegexFlag" | "duplicateRegexFlag") },
|
|
20
|
+
> extends Parser<T> {
|
|
21
|
+
validKeys: string[] = []
|
|
22
|
+
|
|
23
|
+
regexablekeys: string[] = []
|
|
24
|
+
|
|
25
|
+
constructor(
|
|
26
|
+
dummyContext: Record<string, any>,
|
|
27
|
+
validRegexFlags: string[] = ["i", "u", "m"]
|
|
28
|
+
) {
|
|
29
|
+
super({
|
|
30
|
+
arrayValues: false,
|
|
31
|
+
keyParser: (key: string) => key.split(/\.+/),
|
|
32
|
+
keywords: {
|
|
33
|
+
and: [{ isSymbol: true, value: "&&" }],
|
|
34
|
+
or: [{ isSymbol: true, value: "||" }],
|
|
35
|
+
not: [{ isSymbol: true, value: "!" }],
|
|
36
|
+
},
|
|
37
|
+
regexValues: (property, operator) => property !== undefined && operator !== undefined,
|
|
38
|
+
customPropertyOperators: ["!=", "=="],
|
|
39
|
+
prefixableGroups: true,
|
|
40
|
+
prefixApplier: (prefix: string, variable: string) => {
|
|
41
|
+
if (!prefix.endsWith(".")) {
|
|
42
|
+
return `${prefix}.${variable}`
|
|
43
|
+
}
|
|
44
|
+
return prefix + variable
|
|
45
|
+
},
|
|
46
|
+
valueComparer: (_condition, contextValue, query) => {
|
|
47
|
+
if (query.isRegex) {
|
|
48
|
+
return contextValue.match(new RegExp(query.value as string, query.regexFlags ?? "")) !== null
|
|
49
|
+
}
|
|
50
|
+
return contextValue === query.value
|
|
51
|
+
},
|
|
52
|
+
valueValidator: (_contextValue, query): T[] | void => {
|
|
53
|
+
let tokens: T[] = []
|
|
54
|
+
if (!this.validKeys.includes(query.propertyName!)) {
|
|
55
|
+
tokens = tokens.concat(query.property.map(token => ({
|
|
56
|
+
start: token.start,
|
|
57
|
+
end: token.end,
|
|
58
|
+
type: "invalidKey",
|
|
59
|
+
})) as T[])
|
|
60
|
+
}
|
|
61
|
+
if (query.isRegex && !this.regexablekeys.includes(query.propertyName!)) {
|
|
62
|
+
tokens = tokens.concat(query.property.map(token => ({
|
|
63
|
+
start: token.start,
|
|
64
|
+
end: token.end,
|
|
65
|
+
type: "unregexableKey",
|
|
66
|
+
})) as T[])
|
|
67
|
+
}
|
|
68
|
+
if (query.regexFlags) {
|
|
69
|
+
const chars = query.regexFlags.value.split("")
|
|
70
|
+
const start = query.regexFlags.start
|
|
71
|
+
for (let i = 0; i < chars.length; i++) {
|
|
72
|
+
const char = chars[i]
|
|
73
|
+
if (chars.slice(0, i).includes(char)) {
|
|
74
|
+
tokens.push({
|
|
75
|
+
start: start + i,
|
|
76
|
+
end: start + i + 1,
|
|
77
|
+
type: "duplicateRegexFlag",
|
|
78
|
+
} as T)
|
|
79
|
+
}
|
|
80
|
+
if (!validRegexFlags.includes(char)) {
|
|
81
|
+
tokens.push({
|
|
82
|
+
start: start + i,
|
|
83
|
+
end: start + i + 1,
|
|
84
|
+
type: "invalidRegexFlag",
|
|
85
|
+
} as T)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (tokens.length > 0) return tokens
|
|
90
|
+
},
|
|
91
|
+
conditionNormalizer({ operator, value, regexFlags, isRegex, isNegated, isQuoted }: ValueQuery) {
|
|
92
|
+
let finalValue: any = value
|
|
93
|
+
let finalOperator: any = operator
|
|
94
|
+
// another way to allow special unquoted value types is something like this:
|
|
95
|
+
if (typeof value === "string" && !isQuoted) {
|
|
96
|
+
const asNum = parseInt(value, 2)
|
|
97
|
+
if (!isNaN(asNum)) finalValue = asNum
|
|
98
|
+
if (["true", "false"].includes(value)) {
|
|
99
|
+
finalValue = value === "true"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (isRegex) {
|
|
103
|
+
const val = value as string // it's always a string and never prefixed if it's a regex
|
|
104
|
+
const regex = new RegExp(val, regexFlags) // this can throw if the user passes invalid flags
|
|
105
|
+
finalValue = regex
|
|
106
|
+
}
|
|
107
|
+
if (operator) {
|
|
108
|
+
switch (operator as any) {
|
|
109
|
+
case "==": {
|
|
110
|
+
finalOperator = "equals"
|
|
111
|
+
break
|
|
112
|
+
}
|
|
113
|
+
case "!=": {
|
|
114
|
+
finalOperator = "equals"
|
|
115
|
+
isNegated = !isNegated
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { value: finalValue, operator: finalOperator, negate: isNegated }
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
this._extractKeysFromContext(dummyContext)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private _extractKeysFromContext(context: Record<string, any>, prev?: string): void {
|
|
127
|
+
for (const key of Object.keys(context)) {
|
|
128
|
+
if (typeof context[key] === "boolean") {
|
|
129
|
+
this.validKeys.push(prev ? `${prev}.${key}` : key)
|
|
130
|
+
if (context[key] === true) {
|
|
131
|
+
this.regexablekeys.push(prev ? `${prev}.${key}` : key)
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
if (typeof context[key] !== "object") throw new Error("A dummy context value must be a boolean or an object.")
|
|
135
|
+
this._extractKeysFromContext(context[key], prev ? `${prev}.${key}` : key)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
package/src/global.d.ts
ADDED