@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.
Files changed (307) hide show
  1. package/README.md +86 -0
  2. package/dist/ast/builders/array.d.ts +8 -0
  3. package/dist/ast/builders/array.d.ts.map +1 -0
  4. package/dist/ast/builders/array.js +31 -0
  5. package/dist/ast/builders/condition.d.ts +20 -0
  6. package/dist/ast/builders/condition.d.ts.map +1 -0
  7. package/dist/ast/builders/condition.js +28 -0
  8. package/dist/ast/builders/delim.d.ts +11 -0
  9. package/dist/ast/builders/delim.d.ts.map +1 -0
  10. package/dist/ast/builders/delim.js +20 -0
  11. package/dist/ast/builders/error.d.ts +9 -0
  12. package/dist/ast/builders/error.d.ts.map +1 -0
  13. package/dist/ast/builders/error.js +16 -0
  14. package/dist/ast/builders/expression.d.ts +12 -0
  15. package/dist/ast/builders/expression.d.ts.map +1 -0
  16. package/dist/ast/builders/expression.js +31 -0
  17. package/dist/ast/builders/group.d.ts +20 -0
  18. package/dist/ast/builders/group.d.ts.map +1 -0
  19. package/dist/ast/builders/group.js +47 -0
  20. package/dist/ast/builders/index.d.ts +12 -0
  21. package/dist/ast/builders/index.d.ts.map +1 -0
  22. package/dist/ast/builders/index.js +24 -0
  23. package/dist/ast/builders/isFullPos.d.ts +6 -0
  24. package/dist/ast/builders/isFullPos.d.ts.map +1 -0
  25. package/dist/ast/builders/isFullPos.js +6 -0
  26. package/dist/ast/builders/pos.d.ts +21 -0
  27. package/dist/ast/builders/pos.d.ts.map +1 -0
  28. package/dist/ast/builders/pos.js +28 -0
  29. package/dist/ast/builders/token.d.ts +12 -0
  30. package/dist/ast/builders/token.d.ts.map +1 -0
  31. package/dist/ast/builders/token.js +26 -0
  32. package/dist/ast/builders/type.d.ts +6 -0
  33. package/dist/ast/builders/type.d.ts.map +1 -0
  34. package/dist/ast/builders/type.js +37 -0
  35. package/dist/ast/builders/variable.d.ts +17 -0
  36. package/dist/ast/builders/variable.d.ts.map +1 -0
  37. package/dist/ast/builders/variable.js +62 -0
  38. package/dist/ast/classes/ArrayNode.d.ts +18 -0
  39. package/dist/ast/classes/ArrayNode.d.ts.map +1 -0
  40. package/dist/ast/classes/ArrayNode.js +55 -0
  41. package/dist/ast/classes/Condition.d.ts +13 -0
  42. package/dist/ast/classes/Condition.d.ts.map +1 -0
  43. package/dist/ast/classes/Condition.js +21 -0
  44. package/dist/ast/classes/ConditionNode.d.ts +73 -0
  45. package/dist/ast/classes/ConditionNode.d.ts.map +1 -0
  46. package/dist/ast/classes/ConditionNode.js +101 -0
  47. package/dist/ast/classes/ErrorToken.d.ts +27 -0
  48. package/dist/ast/classes/ErrorToken.d.ts.map +1 -0
  49. package/dist/ast/classes/ErrorToken.js +47 -0
  50. package/dist/ast/classes/Expression.d.ts +13 -0
  51. package/dist/ast/classes/Expression.d.ts.map +1 -0
  52. package/dist/ast/classes/Expression.js +19 -0
  53. package/dist/ast/classes/ExpressionNode.d.ts +21 -0
  54. package/dist/ast/classes/ExpressionNode.d.ts.map +1 -0
  55. package/dist/ast/classes/ExpressionNode.js +57 -0
  56. package/dist/ast/classes/GroupNode.d.ts +64 -0
  57. package/dist/ast/classes/GroupNode.d.ts.map +1 -0
  58. package/dist/ast/classes/GroupNode.js +69 -0
  59. package/dist/ast/classes/Node.d.ts +22 -0
  60. package/dist/ast/classes/Node.d.ts.map +1 -0
  61. package/dist/ast/classes/Node.js +28 -0
  62. package/dist/ast/classes/Token.d.ts +27 -0
  63. package/dist/ast/classes/Token.d.ts.map +1 -0
  64. package/dist/ast/classes/Token.js +28 -0
  65. package/dist/ast/classes/ValidToken.d.ts +26 -0
  66. package/dist/ast/classes/ValidToken.d.ts.map +1 -0
  67. package/dist/ast/classes/ValidToken.js +49 -0
  68. package/dist/ast/classes/VariableNode.d.ts +33 -0
  69. package/dist/ast/classes/VariableNode.d.ts.map +1 -0
  70. package/dist/ast/classes/VariableNode.js +58 -0
  71. package/dist/ast/classes/index.d.ts +12 -0
  72. package/dist/ast/classes/index.d.ts.map +1 -0
  73. package/dist/ast/classes/index.js +24 -0
  74. package/dist/ast/handlers.d.ts +42 -0
  75. package/dist/ast/handlers.d.ts.map +1 -0
  76. package/dist/ast/handlers.js +150 -0
  77. package/dist/ast/index.d.ts +4 -0
  78. package/dist/ast/index.d.ts.map +1 -0
  79. package/dist/ast/index.js +8 -0
  80. package/dist/examples/advancedValueComparer.d.ts +3 -0
  81. package/dist/examples/advancedValueComparer.d.ts.map +1 -0
  82. package/dist/examples/advancedValueComparer.js +28 -0
  83. package/dist/examples/shortcutContextParser.d.ts +22 -0
  84. package/dist/examples/shortcutContextParser.d.ts.map +1 -0
  85. package/dist/examples/shortcutContextParser.js +126 -0
  86. package/dist/global.d.js +1 -0
  87. package/dist/grammar/ParserBase.d.ts +51 -0
  88. package/dist/grammar/ParserBase.d.ts.map +1 -0
  89. package/dist/grammar/ParserBase.js +516 -0
  90. package/dist/grammar/createTokens.d.ts +56 -0
  91. package/dist/grammar/createTokens.d.ts.map +1 -0
  92. package/dist/grammar/createTokens.js +843 -0
  93. package/dist/grammar/index.d.ts +3 -0
  94. package/dist/grammar/index.d.ts.map +1 -0
  95. package/dist/grammar/index.js +6 -0
  96. package/dist/helpers/errors.d.ts +9 -0
  97. package/dist/helpers/errors.d.ts.map +1 -0
  98. package/dist/helpers/errors.js +41 -0
  99. package/dist/helpers/general/applyBoolean.d.ts +3 -0
  100. package/dist/helpers/general/applyBoolean.d.ts.map +1 -0
  101. package/dist/helpers/general/applyBoolean.js +17 -0
  102. package/dist/helpers/general/applyPrefix.d.ts +4 -0
  103. package/dist/helpers/general/applyPrefix.d.ts.map +1 -0
  104. package/dist/helpers/general/applyPrefix.js +9 -0
  105. package/dist/helpers/general/defaultConditionNormalizer.d.ts +3 -0
  106. package/dist/helpers/general/defaultConditionNormalizer.d.ts.map +1 -0
  107. package/dist/helpers/general/defaultConditionNormalizer.js +6 -0
  108. package/dist/helpers/general/defaultKeyParser.d.ts +3 -0
  109. package/dist/helpers/general/defaultKeyParser.d.ts.map +1 -0
  110. package/dist/helpers/general/defaultKeyParser.js +8 -0
  111. package/dist/helpers/general/defaultPrefixApplier.d.ts +3 -0
  112. package/dist/helpers/general/defaultPrefixApplier.d.ts.map +1 -0
  113. package/dist/helpers/general/defaultPrefixApplier.js +6 -0
  114. package/dist/helpers/general/defaultValueComparer.d.ts +3 -0
  115. package/dist/helpers/general/defaultValueComparer.d.ts.map +1 -0
  116. package/dist/helpers/general/defaultValueComparer.js +6 -0
  117. package/dist/helpers/general/index.d.ts +7 -0
  118. package/dist/helpers/general/index.d.ts.map +1 -0
  119. package/dist/helpers/general/index.js +14 -0
  120. package/dist/helpers/index.d.ts +4 -0
  121. package/dist/helpers/index.d.ts.map +1 -0
  122. package/dist/helpers/index.js +8 -0
  123. package/dist/helpers/parser/assignParents.d.ts +4 -0
  124. package/dist/helpers/parser/assignParents.d.ts.map +1 -0
  125. package/dist/helpers/parser/assignParents.js +71 -0
  126. package/dist/helpers/parser/checkParserOpts.d.ts +3 -0
  127. package/dist/helpers/parser/checkParserOpts.d.ts.map +1 -0
  128. package/dist/helpers/parser/checkParserOpts.js +126 -0
  129. package/dist/helpers/parser/extractPosition.d.ts +9 -0
  130. package/dist/helpers/parser/extractPosition.d.ts.map +1 -0
  131. package/dist/helpers/parser/extractPosition.js +9 -0
  132. package/dist/helpers/parser/getUnclosedRightParenCount.d.ts +5 -0
  133. package/dist/helpers/parser/getUnclosedRightParenCount.d.ts.map +1 -0
  134. package/dist/helpers/parser/getUnclosedRightParenCount.js +20 -0
  135. package/dist/helpers/parser/index.d.ts +9 -0
  136. package/dist/helpers/parser/index.d.ts.map +1 -0
  137. package/dist/helpers/parser/index.js +18 -0
  138. package/dist/helpers/parser/parseParserOptions.d.ts +4 -0
  139. package/dist/helpers/parser/parseParserOptions.d.ts.map +1 -0
  140. package/dist/helpers/parser/parseParserOptions.js +45 -0
  141. package/dist/helpers/parser/seal.d.ts +8 -0
  142. package/dist/helpers/parser/seal.d.ts.map +1 -0
  143. package/dist/helpers/parser/seal.js +10 -0
  144. package/dist/helpers/parser/setParent.d.ts +6 -0
  145. package/dist/helpers/parser/setParent.d.ts.map +1 -0
  146. package/dist/helpers/parser/setParent.js +4 -0
  147. package/dist/helpers/parser/unescape.d.ts +3 -0
  148. package/dist/helpers/parser/unescape.d.ts.map +1 -0
  149. package/dist/helpers/parser/unescape.js +6 -0
  150. package/dist/index.d.ts +6 -0
  151. package/dist/index.d.ts.map +1 -0
  152. package/dist/index.js +17 -0
  153. package/dist/methods/autocomplete.d.ts +18 -0
  154. package/dist/methods/autocomplete.d.ts.map +1 -0
  155. package/dist/methods/autocomplete.js +109 -0
  156. package/dist/methods/autoreplace.d.ts +13 -0
  157. package/dist/methods/autoreplace.d.ts.map +1 -0
  158. package/dist/methods/autoreplace.js +36 -0
  159. package/dist/methods/autosuggest.d.ts +28 -0
  160. package/dist/methods/autosuggest.d.ts.map +1 -0
  161. package/dist/methods/autosuggest.js +371 -0
  162. package/dist/methods/evaluate.d.ts +11 -0
  163. package/dist/methods/evaluate.d.ts.map +1 -0
  164. package/dist/methods/evaluate.js +30 -0
  165. package/dist/methods/getBestIndex.d.ts +19 -0
  166. package/dist/methods/getBestIndex.d.ts.map +1 -0
  167. package/dist/methods/getBestIndex.js +53 -0
  168. package/dist/methods/getIndexes.d.ts +17 -0
  169. package/dist/methods/getIndexes.d.ts.map +1 -0
  170. package/dist/methods/getIndexes.js +97 -0
  171. package/dist/methods/index.d.ts +9 -0
  172. package/dist/methods/index.d.ts.map +1 -0
  173. package/dist/methods/index.js +18 -0
  174. package/dist/methods/normalize.d.ts +12 -0
  175. package/dist/methods/normalize.d.ts.map +1 -0
  176. package/dist/methods/normalize.js +99 -0
  177. package/dist/methods/validate.d.ts +11 -0
  178. package/dist/methods/validate.d.ts.map +1 -0
  179. package/dist/methods/validate.js +111 -0
  180. package/dist/package.js +7 -0
  181. package/dist/package.json.js +193 -0
  182. package/dist/parser.d.ts +58 -0
  183. package/dist/parser.d.ts.map +1 -0
  184. package/dist/parser.js +136 -0
  185. package/dist/types/ast.d.ts +70 -0
  186. package/dist/types/ast.d.ts.map +1 -0
  187. package/dist/types/ast.js +29 -0
  188. package/dist/types/autocomplete.d.ts +143 -0
  189. package/dist/types/autocomplete.d.ts.map +1 -0
  190. package/dist/types/autocomplete.js +24 -0
  191. package/dist/types/errors.d.ts +34 -0
  192. package/dist/types/errors.d.ts.map +1 -0
  193. package/dist/types/errors.js +10 -0
  194. package/dist/types/index.d.ts +5 -0
  195. package/dist/types/index.d.ts.map +1 -0
  196. package/dist/types/index.js +9 -0
  197. package/dist/types/parser.d.ts +451 -0
  198. package/dist/types/parser.d.ts.map +1 -0
  199. package/dist/types/parser.js +1 -0
  200. package/dist/utils/extractTokens.d.ts +8 -0
  201. package/dist/utils/extractTokens.d.ts.map +1 -0
  202. package/dist/utils/extractTokens.js +50 -0
  203. package/dist/utils/getCursorInfo.d.ts +7 -0
  204. package/dist/utils/getCursorInfo.d.ts.map +1 -0
  205. package/dist/utils/getCursorInfo.js +86 -0
  206. package/dist/utils/getOppositeDelimiter.d.ts +6 -0
  207. package/dist/utils/getOppositeDelimiter.d.ts.map +1 -0
  208. package/dist/utils/getOppositeDelimiter.js +35 -0
  209. package/dist/utils/getSurroundingErrors.d.ts +25 -0
  210. package/dist/utils/getSurroundingErrors.d.ts.map +1 -0
  211. package/dist/utils/getSurroundingErrors.js +37 -0
  212. package/dist/utils/index.d.ts +10 -0
  213. package/dist/utils/index.d.ts.map +1 -0
  214. package/dist/utils/index.js +20 -0
  215. package/dist/utils/isBracket.d.ts +3 -0
  216. package/dist/utils/isBracket.d.ts.map +1 -0
  217. package/dist/utils/isBracket.js +7 -0
  218. package/dist/utils/isDelimiter.d.ts +6 -0
  219. package/dist/utils/isDelimiter.d.ts.map +1 -0
  220. package/dist/utils/isDelimiter.js +17 -0
  221. package/dist/utils/isParen.d.ts +3 -0
  222. package/dist/utils/isParen.d.ts.map +1 -0
  223. package/dist/utils/isParen.js +7 -0
  224. package/dist/utils/isQuote.d.ts +4 -0
  225. package/dist/utils/isQuote.d.ts.map +1 -0
  226. package/dist/utils/isQuote.js +7 -0
  227. package/dist/utils/prettyAst.d.ts +35 -0
  228. package/dist/utils/prettyAst.d.ts.map +1 -0
  229. package/dist/utils/prettyAst.js +112 -0
  230. package/package.json +152 -0
  231. package/src/ast/builders/array.ts +45 -0
  232. package/src/ast/builders/condition.ts +56 -0
  233. package/src/ast/builders/delim.ts +39 -0
  234. package/src/ast/builders/error.ts +22 -0
  235. package/src/ast/builders/expression.ts +66 -0
  236. package/src/ast/builders/group.ts +79 -0
  237. package/src/ast/builders/index.ts +13 -0
  238. package/src/ast/builders/isFullPos.ts +10 -0
  239. package/src/ast/builders/pos.ts +57 -0
  240. package/src/ast/builders/token.ts +46 -0
  241. package/src/ast/builders/type.ts +32 -0
  242. package/src/ast/builders/variable.ts +89 -0
  243. package/src/ast/classes/ArrayNode.ts +46 -0
  244. package/src/ast/classes/Condition.ts +22 -0
  245. package/src/ast/classes/ConditionNode.ts +141 -0
  246. package/src/ast/classes/ErrorToken.ts +49 -0
  247. package/src/ast/classes/Expression.ts +26 -0
  248. package/src/ast/classes/ExpressionNode.ts +62 -0
  249. package/src/ast/classes/GroupNode.ts +127 -0
  250. package/src/ast/classes/Node.ts +47 -0
  251. package/src/ast/classes/Token.ts +59 -0
  252. package/src/ast/classes/ValidToken.ts +56 -0
  253. package/src/ast/classes/VariableNode.ts +67 -0
  254. package/src/ast/classes/index.ts +13 -0
  255. package/src/ast/handlers.ts +190 -0
  256. package/src/ast/index.ts +5 -0
  257. package/src/examples/advancedValueComparer.ts +31 -0
  258. package/src/examples/shortcutContextParser.ts +140 -0
  259. package/src/global.d.ts +4 -0
  260. package/src/grammar/ParserBase.ts +715 -0
  261. package/src/grammar/createTokens.ts +512 -0
  262. package/src/grammar/index.ts +4 -0
  263. package/src/helpers/errors.ts +45 -0
  264. package/src/helpers/general/applyBoolean.ts +9 -0
  265. package/src/helpers/general/applyPrefix.ts +7 -0
  266. package/src/helpers/general/defaultConditionNormalizer.ts +9 -0
  267. package/src/helpers/general/defaultKeyParser.ts +8 -0
  268. package/src/helpers/general/defaultPrefixApplier.ts +7 -0
  269. package/src/helpers/general/defaultValueComparer.ts +7 -0
  270. package/src/helpers/general/index.ts +8 -0
  271. package/src/helpers/index.ts +5 -0
  272. package/src/helpers/parser/assignParents.ts +51 -0
  273. package/src/helpers/parser/checkParserOpts.ts +143 -0
  274. package/src/helpers/parser/extractPosition.ts +15 -0
  275. package/src/helpers/parser/getUnclosedRightParenCount.ts +22 -0
  276. package/src/helpers/parser/index.ts +10 -0
  277. package/src/helpers/parser/parseParserOptions.ts +54 -0
  278. package/src/helpers/parser/seal.ts +14 -0
  279. package/src/helpers/parser/setParent.ts +5 -0
  280. package/src/helpers/parser/unescape.ts +4 -0
  281. package/src/index.ts +7 -0
  282. package/src/methods/autocomplete.ts +128 -0
  283. package/src/methods/autoreplace.ts +46 -0
  284. package/src/methods/autosuggest.ts +543 -0
  285. package/src/methods/evaluate.ts +37 -0
  286. package/src/methods/getBestIndex.ts +53 -0
  287. package/src/methods/getIndexes.ts +99 -0
  288. package/src/methods/index.ts +10 -0
  289. package/src/methods/normalize.ts +138 -0
  290. package/src/methods/validate.ts +141 -0
  291. package/src/package.js +11 -0
  292. package/src/parser.ts +183 -0
  293. package/src/types/ast.ts +148 -0
  294. package/src/types/autocomplete.ts +152 -0
  295. package/src/types/errors.ts +40 -0
  296. package/src/types/index.ts +6 -0
  297. package/src/types/parser.ts +479 -0
  298. package/src/utils/extractTokens.ts +67 -0
  299. package/src/utils/getCursorInfo.ts +106 -0
  300. package/src/utils/getOppositeDelimiter.ts +36 -0
  301. package/src/utils/getSurroundingErrors.ts +57 -0
  302. package/src/utils/index.ts +11 -0
  303. package/src/utils/isBracket.ts +6 -0
  304. package/src/utils/isDelimiter.ts +18 -0
  305. package/src/utils/isParen.ts +6 -0
  306. package/src/utils/isQuote.ts +6 -0
  307. package/src/utils/prettyAst.ts +152 -0
@@ -0,0 +1,143 @@
1
+ import { isBlank, pushIfNotIn } from "@alanscodelog/utils"
2
+
3
+ import { ERROR_CODES } from "../../types/errors.js"
4
+ import type { FullParserOptions, ParserOptions } from "../../types/parser.js"
5
+ import { BooleanParserLibraryError } from "../errors.js"
6
+ import { defaultConditionNormalizer } from "../general/defaultConditionNormalizer.js"
7
+ import { defaultValueComparer } from "../general/defaultValueComparer.js"
8
+
9
+
10
+ export function checkParserOpts<T extends {}>(opts: FullParserOptions<T>, evaluatorChecks: boolean = false, validatorChecks: boolean = false): void {
11
+ if (!evaluatorChecks) {
12
+ const keywordsList = [...opts.keywords.and, ...opts.keywords.or, ...opts.keywords.not].map(keyword => keyword.value)
13
+ const symNots = opts.keywords.not.filter(op => op.isSymbol).map(op => op.value)
14
+ const keywords = [
15
+ ...[...keywordsList].filter(val => !symNots.includes(val)),
16
+ ...["(", ")"],
17
+ ...(opts.arrayValues ? ["[", "]"] : []),
18
+ ...(opts.regexValues ? ["/"] : []),
19
+ ]
20
+ const extra: string[] = []
21
+ if (opts.expandedPropertySeparator) extra.push(opts.expandedPropertySeparator)
22
+ if (opts.customPropertyOperators) pushIfNotIn(extra, ...opts.customPropertyOperators)
23
+
24
+
25
+ /* #region Blank Operator Checks */
26
+ if (opts.expandedPropertySeparator && isBlank(opts.expandedPropertySeparator)) {
27
+ throw new BooleanParserLibraryError(
28
+ ERROR_CODES.PARSER_CONFLICTING_OPTIONS_ERROR,
29
+ { prohibited: [""], invalid: opts.expandedPropertySeparator },
30
+ `expandedPropertySeparator cannot be blank`
31
+ )
32
+ }
33
+ const customInvalid = opts.customPropertyOperators?.find(_ => isBlank(_))
34
+ if (customInvalid !== undefined) {
35
+ throw new BooleanParserLibraryError(
36
+ ERROR_CODES.PARSER_CONFLICTING_OPTIONS_ERROR,
37
+ { prohibited: [""], invalid: customInvalid },
38
+ `customPropertyOperators cannot contain blank entries`
39
+ )
40
+ }
41
+ const prefixInvalid = opts.prefixableStrings?.find(_ => isBlank(_))
42
+ if (prefixInvalid !== undefined) {
43
+ throw new BooleanParserLibraryError(
44
+ ERROR_CODES.PARSER_CONFLICTING_OPTIONS_ERROR,
45
+ { prohibited: [""], invalid: prefixInvalid },
46
+ `prefixableStrings cannot contain blank entries`
47
+ )
48
+ }
49
+ for (const key of ["and", "or", "not"]) {
50
+ const invalid = opts.keywords[key as keyof FullParserOptions["keywords"]]
51
+ ?.find(_ => isBlank(_.value))
52
+ ?.value
53
+ if (invalid !== undefined) {
54
+ throw new BooleanParserLibraryError(
55
+ ERROR_CODES.PARSER_CONFLICTING_OPTIONS_ERROR,
56
+ { prohibited: [""], invalid },
57
+ `keywords.${key} cannot contain entries with blank values`
58
+ )
59
+ }
60
+ }
61
+ /* #regionend */
62
+
63
+ /* #region Prohibited Keyword Checks */
64
+ const all = [...keywords, ...symNots, ...extra]
65
+ const allKeywords = [...keywords, ...symNots]
66
+ /**
67
+ * Allowed:
68
+ * - custom property operators can be the same as symbol not operators
69
+ * - custom property operators can be the same as expanded property separators
70
+ */
71
+
72
+ const messageInvalidAny = "cannot contain operators or special symbols, but found"
73
+ const messageInvalidBool = "cannot contain boolean operators or special symbols, but found"
74
+
75
+ const invalidPrefixableString = opts.prefixableStrings?.find(val => all.includes(val))
76
+ if (invalidPrefixableString) {
77
+ throw new BooleanParserLibraryError(
78
+ ERROR_CODES.PARSER_CONFLICTING_OPTIONS_ERROR,
79
+ { prohibited: all, invalid: invalidPrefixableString },
80
+ `prefixableStrings ${messageInvalidAny} "${invalidPrefixableString}"`
81
+ )
82
+ }
83
+
84
+ const invalidExpandedPropertySeparator = allKeywords
85
+ .find(_ => _ === opts.expandedPropertySeparator as any)
86
+ if (invalidExpandedPropertySeparator) {
87
+ throw new BooleanParserLibraryError(
88
+ ERROR_CODES.PARSER_CONFLICTING_OPTIONS_ERROR,
89
+ { prohibited: allKeywords, invalid: invalidExpandedPropertySeparator },
90
+ `expandedPropertySeparator ${messageInvalidBool} "${invalidExpandedPropertySeparator}"`
91
+ )
92
+ }
93
+
94
+ const invalidCustomPropertyOperator = opts.customPropertyOperators?.find(val => keywords.includes(val))
95
+ ? opts.expandedPropertySeparator
96
+ : undefined
97
+ if (invalidCustomPropertyOperator) {
98
+ throw new BooleanParserLibraryError(
99
+ ERROR_CODES.PARSER_CONFLICTING_OPTIONS_ERROR,
100
+ { prohibited: keywords, invalid: invalidCustomPropertyOperator },
101
+ `customPropertyOperator ${messageInvalidBool} "${invalidCustomPropertyOperator}"`
102
+ )
103
+ }
104
+ /* #regionend */
105
+ }
106
+
107
+ if (evaluatorChecks) {
108
+ const requireCustomNormalizer: (keyof ParserOptions)[] = [] as any
109
+ if ((opts.prefixableStrings?.length ?? 0) > 0) requireCustomNormalizer.push("prefixableStrings")
110
+ if ((opts.customPropertyOperators?.length ?? 0) > 0) requireCustomNormalizer.push("customPropertyOperators")
111
+ if ((opts.expandedPropertySeparator?.length ?? 0) > 0) requireCustomNormalizer.push("expandedPropertySeparator")
112
+ if (opts.regexValues) requireCustomNormalizer.push("regexValues")
113
+
114
+ if (requireCustomNormalizer.length > 0 && opts.conditionNormalizer === defaultConditionNormalizer) {
115
+ throw new BooleanParserLibraryError(
116
+ ERROR_CODES.PARSER_OPTION_REQUIRED_ERROR,
117
+ { options: requireCustomNormalizer, requires: "conditionNormalizer" },
118
+ `A custom conditionNormalizer function must be specified when using the following options: ${requireCustomNormalizer.join(", ")}`
119
+ )
120
+ }
121
+ const requireCustomComparer: (keyof ParserOptions)[] = [] as any
122
+ if (opts.regexValues) requireCustomComparer.push("regexValues")
123
+ if (opts.regexValues) requireCustomComparer.push("arrayValues")
124
+
125
+ if (requireCustomComparer.length > 0 && opts.valueComparer === defaultValueComparer) {
126
+ throw new BooleanParserLibraryError(
127
+ ERROR_CODES.PARSER_OPTION_REQUIRED_ERROR,
128
+ { options: requireCustomComparer, requires: "valueComparer" },
129
+ `A custom valueComparer function must be specified when using the following options: ${requireCustomComparer.join(", ")}`
130
+ )
131
+ }
132
+ }
133
+ if (validatorChecks) {
134
+ if (opts.valueValidator === undefined) {
135
+ throw new BooleanParserLibraryError(
136
+ ERROR_CODES.PARSER_OPTION_REQUIRED_ERROR,
137
+ { requires: "valueValidator" },
138
+ `A custom valueValidator function must be specified when using the validate method.`
139
+ )
140
+ }
141
+ }
142
+ }
143
+
@@ -0,0 +1,15 @@
1
+ import type { Position } from "../../types/ast.js"
2
+
3
+
4
+ type ChevrotainLocation = {
5
+ startOffset?: number
6
+ endOffset?: number
7
+ }
8
+
9
+ /** @internal */
10
+ export function extractPosition(loc: ChevrotainLocation, shift: number): Position {
11
+ return {
12
+ start: loc.startOffset! - (shift ?? 0),
13
+ end: loc.endOffset! + 1 - (shift ?? 0),
14
+ }
15
+ }
@@ -0,0 +1,22 @@
1
+ import { type IToken, tokenMatcher } from "chevrotain"
2
+
3
+ import type { createTokens } from "../../grammar/createTokens.js"
4
+
5
+
6
+ /** @internal */
7
+ export function getUnclosedRightParenCount(tokens: IToken[], t: ReturnType<typeof createTokens>["tokens"]): number {
8
+ let open = 0
9
+ let unclosed = 0
10
+ for (const token of tokens) {
11
+ if (tokenMatcher(token, t.PAREN_R)) {
12
+ if (open > 0) {
13
+ open--
14
+ } else {
15
+ unclosed++
16
+ }
17
+ } else if (tokenMatcher(token, t.PAREN_L)) {
18
+ open++
19
+ }
20
+ }
21
+ return unclosed
22
+ }
@@ -0,0 +1,10 @@
1
+ /* Autogenerated Index */
2
+
3
+ export { assignParents } from "./assignParents.js"
4
+ export { checkParserOpts } from "./checkParserOpts.js"
5
+ export { extractPosition } from "./extractPosition.js"
6
+ export { getUnclosedRightParenCount } from "./getUnclosedRightParenCount.js"
7
+ export { parseParserOptions } from "./parseParserOptions.js"
8
+ export { seal } from "./seal.js"
9
+ export { setParent } from "./setParent.js"
10
+ export { unescape } from "./unescape.js"
@@ -0,0 +1,54 @@
1
+ import type { FullParserOptions, ParserOptions } from "../../types/parser.js"
2
+ import { defaultConditionNormalizer } from "../general/defaultConditionNormalizer.js"
3
+ import { defaultKeyParser } from "../general/defaultKeyParser.js"
4
+ import { defaultPrefixApplier } from "../general/defaultPrefixApplier.js"
5
+ import { defaultValueComparer } from "../general/defaultValueComparer.js"
6
+
7
+ /** @internal */
8
+ export function parseParserOptions<T extends {} = {}>(
9
+ options: ParserOptions<T>
10
+ ): FullParserOptions<T> {
11
+ const opts: ParserOptions = {
12
+ prefixApplier: defaultPrefixApplier,
13
+ keyParser: defaultKeyParser,
14
+ valueComparer: defaultValueComparer,
15
+ conditionNormalizer: defaultConditionNormalizer,
16
+ prefixableGroups: true,
17
+ prefixableStrings: undefined,
18
+ expandedPropertySeparator: undefined,
19
+ customPropertyOperators: undefined,
20
+ onMissingBooleanOperator: "error",
21
+ arrayValues: true,
22
+ regexValues: true,
23
+ ...options, // todo fix
24
+ keywords: {
25
+ or:
26
+ options.keywords?.or
27
+ ? options.keywords.or as any
28
+ : [
29
+ { value: "||", isSymbol: true },
30
+ { value: "|", isSymbol: true },
31
+ { value: "or", isSymbol: false },
32
+ { value: "OR", isSymbol: false },
33
+ ],
34
+ and:
35
+ options.keywords?.and
36
+ ? options.keywords.and as any
37
+ : [
38
+ { value: "&&", isSymbol: true },
39
+ { value: "&", isSymbol: true },
40
+ { value: "and", isSymbol: false },
41
+ { value: "AND", isSymbol: false },
42
+ ],
43
+ not:
44
+ options.keywords?.not
45
+ ? options.keywords.not as any
46
+ : [
47
+ { value: "!", isSymbol: true },
48
+ { value: "not", isSymbol: false },
49
+ { value: "NOT", isSymbol: false },
50
+ ],
51
+ },
52
+ }
53
+ return opts as any
54
+ }
@@ -0,0 +1,14 @@
1
+ import { assignParents } from "./assignParents.js"
2
+
3
+ import { Node } from "../../ast/classes/Node.js"
4
+ import type { AnyToken, Nodes } from "../../types/ast.js"
5
+
6
+ /**
7
+ * set and "seals" all parent properties
8
+ *
9
+ * @internal
10
+ */
11
+ export function seal(ast: Nodes | AnyToken): void {
12
+ if (ast instanceof Node) assignParents(ast)
13
+ ast.parent = undefined
14
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @internal
3
+ * @see assignParents
4
+ */
5
+ export const setParent: unique symbol = Symbol("private set parent key")
@@ -0,0 +1,4 @@
1
+ /** @internal */
2
+ export function unescape(str: string): string {
3
+ return str.replace(/\\{1,1}(.)/g, "$1")
4
+ }
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ /* Manually Generated Index */
2
+ export * as ast from "./ast/classes/index.js"
3
+ export * as grammar from "./grammar/index.js"
4
+ export { Parser } from "./parser.js"
5
+ export * from "./types/index.js"
6
+ export * as utils from "./utils/index.js"
7
+
@@ -0,0 +1,128 @@
1
+ import { unreachable } from "@alanscodelog/utils"
2
+
3
+ import { ConditionNode } from "../ast/classes/ConditionNode.js"
4
+ import { VariableNode } from "../ast/classes/VariableNode.js"
5
+ import type { Parser } from "../parser.js"
6
+ import { type Completion, type Suggestion, SUGGESTION_TYPE } from "../types/autocomplete.js"
7
+ import type { FullParserOptions } from "../types/parser.js"
8
+
9
+
10
+ export class AutocompleteMixin<T extends {}> {
11
+ /**
12
+ * Given a list of @see Suggestion entries, the parser options, and a list of variables, prefixes, operators, etc, and the preferred quote type, returns a list of @see Completion entries.
13
+ *
14
+ * It takes care of suggesting the correct delimiters for fixes, quoting variables/prefixes if it would not be possible to parse them unquoted, and separating symbol from non-symbol (word) operators.
15
+ *
16
+ * Does not add whitespace or group requirements. The suggestion information is still in the completion if you wish to show these. But they should not be added to the completion value if using @see autoreplace which will take care of it.
17
+ *
18
+ * Is not aware of existing values. You will have to use @see getCursorInfo to understand the context in which the suggestion was made, so that, for example, you could filter out used regex flags.
19
+ */
20
+ autocomplete(
21
+ suggestions: Suggestion[],
22
+ {
23
+ values = [], arrayValues = [], variables = [], prefixes = [], properties = [], expandedPropertyOperators = [], customPropertyOperators = (this as any as Parser<T>).options.customPropertyOperators ?? [], keywords = (this as any as Parser<T>).options.keywords, regexFlags = ["i", "m", "u"], quote = "\"",
24
+ }: Partial<Record<
25
+ "variables" |
26
+ "values" |
27
+ "arrayValues" |
28
+ "prefixes" |
29
+ "properties" |
30
+ "regexFlags" |
31
+ "expandedPropertyOperators" |
32
+ "customPropertyOperators", string[]>> & {
33
+ quote?: string
34
+ keywords?: FullParserOptions<T>["keywords"]
35
+ } = {}
36
+ ): Completion[] {
37
+ const self = (this as any as Parser<T>)
38
+ return suggestions.map(suggestion => {
39
+ const type = suggestion.type
40
+ switch (type) {
41
+ case SUGGESTION_TYPE.BACKTICK: return [{ suggestion, value: "`" }]
42
+ case SUGGESTION_TYPE.DOUBLEQUOTE: return [{ suggestion, value: "\"" }]
43
+ case SUGGESTION_TYPE.SINGLEQUOTE: return [{ suggestion, value: "'" }]
44
+ case SUGGESTION_TYPE.PARENL: return [{ suggestion, value: "(" }]
45
+ case SUGGESTION_TYPE.PARENR: return [{ suggestion, value: ")" }]
46
+ case SUGGESTION_TYPE.BRAKCETR: return [{ suggestion, value: "]" }] // L not needed
47
+ case SUGGESTION_TYPE.REGEX: return [{ suggestion, value: "/" }]
48
+ case SUGGESTION_TYPE.REGEX_FLAGS:
49
+ return regexFlags
50
+ .map(value => ({ suggestion, value }))
51
+ // remove existing flags from suggestions
52
+ .filter(completion => {
53
+ // eslint-disable-next-line @typescript-eslint/no-shadow
54
+ const { suggestion, value } = completion
55
+ if (suggestion.type !== SUGGESTION_TYPE.REGEX_FLAGS) {return true}
56
+
57
+ const token = suggestion.cursorInfo
58
+ const flags = token.at && (token.at.parent as VariableNode)?.quote?.flags === suggestion.cursorInfo.at
59
+ ? token.at
60
+ : token.next && (token.next.parent as VariableNode)?.quote?.flags === suggestion.cursorInfo.next
61
+ ? token.next
62
+ : token.prev && (token.prev.parent as VariableNode)?.quote?.flags === suggestion.cursorInfo.prev
63
+ ? token.prev
64
+ : undefined
65
+
66
+ if (flags?.value?.includes(value)) {return false}
67
+ return true
68
+ })
69
+ case SUGGESTION_TYPE.PROPERTY: {
70
+ return properties.map(value => ({ suggestion, value }))
71
+ }
72
+ case SUGGESTION_TYPE.PROPERTY_SEP: {
73
+ return [{ suggestion, value: self.options.expandedPropertySeparator! }]
74
+ }
75
+ case SUGGESTION_TYPE.EXPANDED_PROPERTY_OPERATOR: {
76
+ return expandedPropertyOperators.map(value => ({ suggestion, value }))
77
+ }
78
+ case SUGGESTION_TYPE.CUSTOM_PROPERTY_OPERATOR: {
79
+ return customPropertyOperators.map(value => ({ suggestion, value }))
80
+ }
81
+ case SUGGESTION_TYPE.BOOLEAN_SYMBOL_OP: {
82
+ const keywordsList = [...keywords.and, ...keywords.or]
83
+ const symOpts = keywordsList.filter(_ => _.isSymbol)
84
+ return symOpts.map(({ value }) => ({ suggestion, value }))
85
+ }
86
+ case SUGGESTION_TYPE.BOOLEAN_WORD_OP: {
87
+ const keywordsList = [...keywords.and, ...keywords.or]
88
+ const wordOpts = keywordsList.filter(_ => !_.isSymbol)
89
+ return wordOpts.map(({ value }) => ({ suggestion, value }))
90
+ }
91
+ case SUGGESTION_TYPE.VALUE:
92
+ case SUGGESTION_TYPE.ARRAY_VALUE:
93
+ case SUGGESTION_TYPE.VARIABLE: {
94
+ const arr = type === SUGGESTION_TYPE.VARIABLE
95
+ ? variables
96
+ : type === SUGGESTION_TYPE.ARRAY_VALUE
97
+ ? arrayValues
98
+ : type === SUGGESTION_TYPE.VALUE
99
+ ? values
100
+ : unreachable()
101
+ return arr.map(variable => {
102
+ // we don't need to alter options since we can just check there are no quotes (also tells us no prefixes are used) and no operators are defined
103
+ const res = self.parse(variable)
104
+ if (res instanceof ConditionNode &&
105
+ res.operator === undefined &&
106
+ res.value instanceof VariableNode &&
107
+ res.value.quote === undefined) {
108
+ return { suggestion, value: res.value.value.value }
109
+ } else {
110
+ return { suggestion, value: quote + variable.replace(new RegExp(quote, "g"), `\\${quote}`) + quote }
111
+ }
112
+ })
113
+ }
114
+ case SUGGESTION_TYPE.PREFIX: return prefixes.map(prefix => {
115
+ const res = self.parse(prefix)
116
+ if (res instanceof ConditionNode &&
117
+ res.operator === undefined &&
118
+ res.value instanceof VariableNode &&
119
+ res.value.quote === undefined) {
120
+ return { suggestion, value: res.value.value.value }
121
+ } else {
122
+ return { suggestion, value: quote + prefix.replace(new RegExp(quote, "g"), `\\${quote}`) + quote }
123
+ }
124
+ })
125
+ }
126
+ }).flat()
127
+ }
128
+ }
@@ -0,0 +1,46 @@
1
+ import { insert } from "@alanscodelog/utils"
2
+
3
+ import type { Completion } from "../types/autocomplete.js"
4
+
5
+
6
+ export class AutoreplaceMixin {
7
+ /**
8
+ * Given the input string and a @see Completion consisting of the value of the replacement and a @see Suggestion entry, returns the replacement string and the new position of the cursor.
9
+ *
10
+ * The value passed should be escaped if it's needed (or quoted). @see autocomplete already takes care of quoting variables if you're using it.
11
+ */
12
+ autoreplace(
13
+ input: string,
14
+ { value, suggestion }: Completion
15
+ ): { replacement: string, cursor: number } {
16
+ const isQuotedLeft = ["\"", "'", "`"].includes(value[0])
17
+ const isQuotedRight = ["\"", "'", "`"].includes(value[value.length - 1])
18
+ if ((isQuotedLeft && !isQuotedRight) || (!isQuotedLeft && isQuotedRight)) {
19
+ throw new Error(`Completion value must either be entirely quoted or entirely unquoted. But the left side is ${isQuotedLeft ? "quoted" : "unquoted"} and the right side is ${isQuotedRight ? "quoted" : "unquoted"}.`)
20
+ }
21
+ let cursor = suggestion.range.start + value.length
22
+
23
+ if (suggestion.requires.prefix) {
24
+ value = suggestion.requires.prefix + (isQuotedLeft ? "" : "\"") + value + (isQuotedRight ? "" : "\"")
25
+
26
+ cursor += suggestion.requires.prefix.length + Number(!isQuotedLeft) + Number(!isQuotedRight)
27
+ }
28
+ if (suggestion.requires.group) {
29
+ value += "()"
30
+ cursor++
31
+ }
32
+
33
+ if (suggestion.requires.whitespace.before // &&
34
+ ) {
35
+ value = ` ${value}`
36
+ cursor++
37
+ }
38
+ if (suggestion.requires.whitespace.after // &&
39
+ ) {
40
+ value = `${value} `
41
+ }
42
+
43
+ const replacement = insert(value, input, [suggestion.range.start, suggestion.range.end])
44
+ return { replacement, cursor }
45
+ }
46
+ }