@witchcraft/expressit 0.1.2 → 0.2.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.
Files changed (285) hide show
  1. package/README.md +9 -5
  2. package/dist/Lexer.js +2 -2
  3. package/dist/Parser.d.ts +14 -29
  4. package/dist/Parser.d.ts.map +1 -1
  5. package/dist/Parser.js +120 -135
  6. package/dist/ast/builders/array.d.ts +1 -3
  7. package/dist/ast/builders/array.d.ts.map +1 -1
  8. package/dist/ast/builders/array.js +3 -5
  9. package/dist/ast/builders/condition.d.ts +5 -11
  10. package/dist/ast/builders/condition.d.ts.map +1 -1
  11. package/dist/ast/builders/condition.js +2 -3
  12. package/dist/ast/builders/delim.d.ts +1 -1
  13. package/dist/ast/builders/error.d.ts +3 -4
  14. package/dist/ast/builders/error.d.ts.map +1 -1
  15. package/dist/ast/builders/error.js +6 -2
  16. package/dist/ast/builders/expression.d.ts +3 -7
  17. package/dist/ast/builders/expression.d.ts.map +1 -1
  18. package/dist/ast/builders/expression.js +3 -5
  19. package/dist/ast/builders/group.d.ts +3 -8
  20. package/dist/ast/builders/group.d.ts.map +1 -1
  21. package/dist/ast/builders/group.js +3 -3
  22. package/dist/ast/builders/pos.d.ts +1 -2
  23. package/dist/ast/builders/pos.d.ts.map +1 -1
  24. package/dist/ast/builders/token.d.ts +3 -5
  25. package/dist/ast/builders/token.d.ts.map +1 -1
  26. package/dist/ast/builders/token.js +3 -4
  27. package/dist/ast/builders/type.d.ts +1 -1
  28. package/dist/ast/builders/variable.d.ts +3 -5
  29. package/dist/ast/builders/variable.d.ts.map +1 -1
  30. package/dist/ast/builders/variable.js +2 -3
  31. package/dist/ast/createArrayNode.d.ts +3 -0
  32. package/dist/ast/createArrayNode.d.ts.map +1 -0
  33. package/dist/ast/createArrayNode.js +12 -0
  34. package/dist/ast/createConditionNode.d.ts +11 -0
  35. package/dist/ast/createConditionNode.d.ts.map +1 -0
  36. package/dist/ast/createConditionNode.js +18 -0
  37. package/dist/ast/createExpressionNode.d.ts +3 -0
  38. package/dist/ast/createExpressionNode.d.ts.map +1 -0
  39. package/dist/ast/createExpressionNode.js +14 -0
  40. package/dist/ast/createGroupNode.d.ts +5 -0
  41. package/dist/ast/createGroupNode.d.ts.map +1 -0
  42. package/dist/ast/createGroupNode.js +14 -0
  43. package/dist/ast/createNormalizedCondition.d.ts +3 -0
  44. package/dist/ast/createNormalizedCondition.d.ts.map +1 -0
  45. package/dist/ast/createNormalizedCondition.js +10 -0
  46. package/dist/ast/createNormalizedExpression.d.ts +3 -0
  47. package/dist/ast/createNormalizedExpression.d.ts.map +1 -0
  48. package/dist/ast/createNormalizedExpression.js +10 -0
  49. package/dist/ast/createToken.d.ts +6 -0
  50. package/dist/ast/createToken.d.ts.map +1 -0
  51. package/dist/ast/createToken.js +15 -0
  52. package/dist/ast/createVariableNode.d.ts +3 -0
  53. package/dist/ast/createVariableNode.d.ts.map +1 -0
  54. package/dist/ast/createVariableNode.js +12 -0
  55. package/dist/ast/error.d.ts +3 -0
  56. package/dist/ast/error.d.ts.map +1 -0
  57. package/dist/ast/error.js +9 -0
  58. package/dist/ast/handlers.d.ts +5 -12
  59. package/dist/ast/handlers.d.ts.map +1 -1
  60. package/dist/ast/handlers.js +21 -29
  61. package/dist/ast/index.d.ts +9 -1
  62. package/dist/ast/index.d.ts.map +1 -1
  63. package/dist/ast/index.js +18 -2
  64. package/dist/defaults/defaultConditionNormalizer.d.ts +3 -0
  65. package/dist/defaults/defaultConditionNormalizer.d.ts.map +1 -0
  66. package/dist/defaults/defaultKeyParser.d.ts +3 -0
  67. package/dist/defaults/defaultKeyParser.d.ts.map +1 -0
  68. package/dist/defaults/defaultPrefixApplier.d.ts +3 -0
  69. package/dist/defaults/defaultPrefixApplier.d.ts.map +1 -0
  70. package/dist/defaults/defaultValueComparer.d.ts +3 -0
  71. package/dist/defaults/defaultValueComparer.d.ts.map +1 -0
  72. package/dist/{helpers/general → defaults}/index.d.ts +0 -2
  73. package/dist/defaults/index.d.ts.map +1 -0
  74. package/dist/{helpers/general → defaults}/index.js +0 -4
  75. package/dist/index.d.ts +2 -1
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +3 -1
  78. package/dist/{helpers/errors.d.ts → internal/ExpressitError.d.ts} +3 -2
  79. package/dist/internal/ExpressitError.d.ts.map +1 -0
  80. package/dist/{helpers/errors.js → internal/ExpressitError.js} +2 -2
  81. package/dist/internal/applyBoolean.d.ts.map +1 -0
  82. package/dist/{helpers/general → internal}/applyPrefix.d.ts +1 -1
  83. package/dist/internal/applyPrefix.d.ts.map +1 -0
  84. package/dist/{helpers/parser → internal}/checkParserOpts.d.ts +2 -1
  85. package/dist/internal/checkParserOpts.d.ts.map +1 -0
  86. package/dist/{helpers/parser → internal}/checkParserOpts.js +14 -14
  87. package/dist/internal/escapeVariableOrPrefix.d.ts +2 -0
  88. package/dist/internal/escapeVariableOrPrefix.d.ts.map +1 -0
  89. package/dist/internal/escapeVariableOrPrefix.js +38 -0
  90. package/dist/internal/extractPosition.d.ts +5 -0
  91. package/dist/internal/extractPosition.d.ts.map +1 -0
  92. package/dist/internal/getUnclosedRightParenCount.d.ts +4 -0
  93. package/dist/internal/getUnclosedRightParenCount.d.ts.map +1 -0
  94. package/dist/{helpers/parser → internal}/getUnclosedRightParenCount.js +1 -1
  95. package/dist/{helpers/parser → internal}/parseParserOptions.d.ts +1 -1
  96. package/dist/internal/parseParserOptions.d.ts.map +1 -0
  97. package/dist/{helpers/parser → internal}/parseParserOptions.js +4 -4
  98. package/dist/internal/unescape.d.ts.map +1 -0
  99. package/dist/package.json.js +7 -7
  100. package/dist/types/ast.d.ts +195 -6
  101. package/dist/types/ast.d.ts.map +1 -1
  102. package/dist/types/ast.js +2 -0
  103. package/dist/types/autocomplete.d.ts +5 -6
  104. package/dist/types/autocomplete.d.ts.map +1 -1
  105. package/dist/types/parser.d.ts +17 -22
  106. package/dist/types/parser.d.ts.map +1 -1
  107. package/dist/utils/extractTokens.d.ts +2 -4
  108. package/dist/utils/extractTokens.d.ts.map +1 -1
  109. package/dist/utils/extractTokens.js +14 -18
  110. package/dist/utils/generateParentsMap.d.ts +10 -0
  111. package/dist/utils/generateParentsMap.d.ts.map +1 -0
  112. package/dist/utils/generateParentsMap.js +73 -0
  113. package/dist/utils/getCursorInfo.d.ts +1 -1
  114. package/dist/utils/getCursorInfo.d.ts.map +1 -1
  115. package/dist/utils/getCursorInfo.js +3 -5
  116. package/dist/utils/getOppositeDelimiter.d.ts +2 -1
  117. package/dist/utils/getOppositeDelimiter.d.ts.map +1 -1
  118. package/dist/utils/getOppositeDelimiter.js +6 -5
  119. package/dist/utils/getParent.d.ts +5 -0
  120. package/dist/utils/getParent.d.ts.map +1 -0
  121. package/dist/utils/getParent.js +6 -0
  122. package/dist/utils/getSurroundingErrors.d.ts +3 -4
  123. package/dist/utils/getSurroundingErrors.d.ts.map +1 -1
  124. package/dist/utils/getSurroundingErrors.js +3 -3
  125. package/dist/utils/index.d.ts +4 -0
  126. package/dist/utils/index.d.ts.map +1 -1
  127. package/dist/utils/index.js +8 -0
  128. package/dist/utils/isNode.d.ts +10 -0
  129. package/dist/utils/isNode.d.ts.map +1 -0
  130. package/dist/utils/isNode.js +6 -0
  131. package/dist/utils/isToken.d.ts +8 -0
  132. package/dist/utils/isToken.d.ts.map +1 -0
  133. package/dist/utils/isToken.js +6 -0
  134. package/dist/utils/prettyAst.d.ts +1 -2
  135. package/dist/utils/prettyAst.d.ts.map +1 -1
  136. package/dist/utils/prettyAst.js +19 -26
  137. package/package.json +7 -7
  138. package/src/Lexer.ts +2 -2
  139. package/src/Parser.ts +158 -165
  140. package/src/ast/builders/array.ts +4 -9
  141. package/src/ast/builders/condition.ts +10 -15
  142. package/src/ast/builders/delim.ts +1 -1
  143. package/src/ast/builders/error.ts +10 -6
  144. package/src/ast/builders/expression.ts +17 -23
  145. package/src/ast/builders/group.ts +7 -11
  146. package/src/ast/builders/pos.ts +2 -3
  147. package/src/ast/builders/token.ts +6 -7
  148. package/src/ast/builders/type.ts +1 -1
  149. package/src/ast/builders/variable.ts +6 -8
  150. package/src/ast/createArrayNode.ts +17 -0
  151. package/src/ast/createConditionNode.ts +58 -0
  152. package/src/ast/createExpressionNode.ts +21 -0
  153. package/src/ast/createGroupNode.ts +46 -0
  154. package/src/ast/createNormalizedCondition.ts +12 -0
  155. package/src/ast/createNormalizedExpression.ts +9 -0
  156. package/src/ast/createToken.ts +26 -0
  157. package/src/ast/createVariableNode.ts +18 -0
  158. package/src/ast/error.ts +9 -0
  159. package/src/ast/handlers.ts +26 -37
  160. package/src/ast/index.ts +9 -1
  161. package/src/{helpers/general → defaults}/defaultConditionNormalizer.ts +1 -1
  162. package/src/{helpers/general → defaults}/defaultKeyParser.ts +1 -1
  163. package/src/{helpers/general → defaults}/defaultPrefixApplier.ts +1 -1
  164. package/src/{helpers/general → defaults}/defaultValueComparer.ts +1 -1
  165. package/src/{helpers/general → defaults}/index.ts +0 -2
  166. package/src/index.ts +2 -1
  167. package/src/{helpers/errors.ts → internal/ExpressitError.ts} +2 -2
  168. package/src/{helpers/general → internal}/applyPrefix.ts +1 -1
  169. package/src/{helpers/parser → internal}/checkParserOpts.ts +16 -15
  170. package/src/internal/escapeVariableOrPrefix.ts +36 -0
  171. package/src/{helpers/parser → internal}/extractPosition.ts +2 -2
  172. package/src/{helpers/parser → internal}/getUnclosedRightParenCount.ts +1 -2
  173. package/src/{helpers/parser → internal}/parseParserOptions.ts +5 -5
  174. package/src/types/ast.ts +292 -7
  175. package/src/types/autocomplete.ts +5 -7
  176. package/src/types/parser.ts +17 -22
  177. package/src/utils/extractTokens.ts +16 -20
  178. package/src/utils/generateParentsMap.ts +60 -0
  179. package/src/utils/getCursorInfo.ts +4 -6
  180. package/src/utils/getOppositeDelimiter.ts +11 -10
  181. package/src/utils/getParent.ts +16 -0
  182. package/src/utils/getSurroundingErrors.ts +10 -9
  183. package/src/utils/index.ts +4 -0
  184. package/src/utils/isNode.ts +12 -0
  185. package/src/utils/isToken.ts +10 -0
  186. package/src/utils/prettyAst.ts +20 -17
  187. package/dist/ast/classes/ArrayNode.d.ts +0 -18
  188. package/dist/ast/classes/ArrayNode.d.ts.map +0 -1
  189. package/dist/ast/classes/ArrayNode.js +0 -55
  190. package/dist/ast/classes/Condition.d.ts +0 -13
  191. package/dist/ast/classes/Condition.d.ts.map +0 -1
  192. package/dist/ast/classes/Condition.js +0 -21
  193. package/dist/ast/classes/ConditionNode.d.ts +0 -73
  194. package/dist/ast/classes/ConditionNode.d.ts.map +0 -1
  195. package/dist/ast/classes/ConditionNode.js +0 -101
  196. package/dist/ast/classes/ErrorToken.d.ts +0 -27
  197. package/dist/ast/classes/ErrorToken.d.ts.map +0 -1
  198. package/dist/ast/classes/ErrorToken.js +0 -47
  199. package/dist/ast/classes/Expression.d.ts +0 -13
  200. package/dist/ast/classes/Expression.d.ts.map +0 -1
  201. package/dist/ast/classes/Expression.js +0 -19
  202. package/dist/ast/classes/ExpressionNode.d.ts +0 -21
  203. package/dist/ast/classes/ExpressionNode.d.ts.map +0 -1
  204. package/dist/ast/classes/ExpressionNode.js +0 -57
  205. package/dist/ast/classes/GroupNode.d.ts +0 -64
  206. package/dist/ast/classes/GroupNode.d.ts.map +0 -1
  207. package/dist/ast/classes/GroupNode.js +0 -69
  208. package/dist/ast/classes/Node.d.ts +0 -22
  209. package/dist/ast/classes/Node.d.ts.map +0 -1
  210. package/dist/ast/classes/Node.js +0 -28
  211. package/dist/ast/classes/Token.d.ts +0 -27
  212. package/dist/ast/classes/Token.d.ts.map +0 -1
  213. package/dist/ast/classes/Token.js +0 -28
  214. package/dist/ast/classes/ValidToken.d.ts +0 -26
  215. package/dist/ast/classes/ValidToken.d.ts.map +0 -1
  216. package/dist/ast/classes/ValidToken.js +0 -49
  217. package/dist/ast/classes/VariableNode.d.ts +0 -33
  218. package/dist/ast/classes/VariableNode.d.ts.map +0 -1
  219. package/dist/ast/classes/VariableNode.js +0 -58
  220. package/dist/ast/classes/index.d.ts +0 -12
  221. package/dist/ast/classes/index.d.ts.map +0 -1
  222. package/dist/ast/classes/index.js +0 -24
  223. package/dist/helpers/errors.d.ts.map +0 -1
  224. package/dist/helpers/general/applyBoolean.d.ts.map +0 -1
  225. package/dist/helpers/general/applyPrefix.d.ts.map +0 -1
  226. package/dist/helpers/general/defaultConditionNormalizer.d.ts +0 -3
  227. package/dist/helpers/general/defaultConditionNormalizer.d.ts.map +0 -1
  228. package/dist/helpers/general/defaultKeyParser.d.ts +0 -3
  229. package/dist/helpers/general/defaultKeyParser.d.ts.map +0 -1
  230. package/dist/helpers/general/defaultPrefixApplier.d.ts +0 -3
  231. package/dist/helpers/general/defaultPrefixApplier.d.ts.map +0 -1
  232. package/dist/helpers/general/defaultValueComparer.d.ts +0 -3
  233. package/dist/helpers/general/defaultValueComparer.d.ts.map +0 -1
  234. package/dist/helpers/general/index.d.ts.map +0 -1
  235. package/dist/helpers/index.d.ts +0 -4
  236. package/dist/helpers/index.d.ts.map +0 -1
  237. package/dist/helpers/index.js +0 -8
  238. package/dist/helpers/parser/assignParents.d.ts +0 -4
  239. package/dist/helpers/parser/assignParents.d.ts.map +0 -1
  240. package/dist/helpers/parser/assignParents.js +0 -71
  241. package/dist/helpers/parser/checkParserOpts.d.ts.map +0 -1
  242. package/dist/helpers/parser/extractPosition.d.ts +0 -5
  243. package/dist/helpers/parser/extractPosition.d.ts.map +0 -1
  244. package/dist/helpers/parser/getUnclosedRightParenCount.d.ts +0 -4
  245. package/dist/helpers/parser/getUnclosedRightParenCount.d.ts.map +0 -1
  246. package/dist/helpers/parser/index.d.ts +0 -9
  247. package/dist/helpers/parser/index.d.ts.map +0 -1
  248. package/dist/helpers/parser/index.js +0 -18
  249. package/dist/helpers/parser/parseParserOptions.d.ts.map +0 -1
  250. package/dist/helpers/parser/seal.d.ts +0 -8
  251. package/dist/helpers/parser/seal.d.ts.map +0 -1
  252. package/dist/helpers/parser/seal.js +0 -10
  253. package/dist/helpers/parser/setParent.d.ts +0 -6
  254. package/dist/helpers/parser/setParent.d.ts.map +0 -1
  255. package/dist/helpers/parser/setParent.js +0 -4
  256. package/dist/helpers/parser/unescape.d.ts.map +0 -1
  257. package/src/ast/classes/ArrayNode.ts +0 -46
  258. package/src/ast/classes/Condition.ts +0 -22
  259. package/src/ast/classes/ConditionNode.ts +0 -141
  260. package/src/ast/classes/ErrorToken.ts +0 -49
  261. package/src/ast/classes/Expression.ts +0 -26
  262. package/src/ast/classes/ExpressionNode.ts +0 -62
  263. package/src/ast/classes/GroupNode.ts +0 -127
  264. package/src/ast/classes/Node.ts +0 -47
  265. package/src/ast/classes/Token.ts +0 -59
  266. package/src/ast/classes/ValidToken.ts +0 -56
  267. package/src/ast/classes/VariableNode.ts +0 -67
  268. package/src/ast/classes/index.ts +0 -13
  269. package/src/helpers/index.ts +0 -6
  270. package/src/helpers/parser/assignParents.ts +0 -51
  271. package/src/helpers/parser/index.ts +0 -10
  272. package/src/helpers/parser/seal.ts +0 -14
  273. package/src/helpers/parser/setParent.ts +0 -5
  274. /package/dist/{helpers/general → defaults}/defaultConditionNormalizer.js +0 -0
  275. /package/dist/{helpers/general → defaults}/defaultKeyParser.js +0 -0
  276. /package/dist/{helpers/general → defaults}/defaultPrefixApplier.js +0 -0
  277. /package/dist/{helpers/general → defaults}/defaultValueComparer.js +0 -0
  278. /package/dist/{helpers/general → internal}/applyBoolean.d.ts +0 -0
  279. /package/dist/{helpers/general → internal}/applyBoolean.js +0 -0
  280. /package/dist/{helpers/general → internal}/applyPrefix.js +0 -0
  281. /package/dist/{helpers/parser → internal}/extractPosition.js +0 -0
  282. /package/dist/{helpers/parser → internal}/unescape.d.ts +0 -0
  283. /package/dist/{helpers/parser → internal}/unescape.js +0 -0
  284. /package/src/{helpers/general → internal}/applyBoolean.ts +0 -0
  285. /package/src/{helpers/parser → internal}/unescape.ts +0 -0
package/src/types/ast.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import type { AnyFunction } from "@alanscodelog/utils/types"
2
2
 
3
- import type { ArrayNode, ConditionNode, ErrorToken, ExpressionNode, GroupNode, ValidToken, VariableNode } from "../ast/classes/index.js"
4
3
 
5
4
  export type AddParameters<T extends AnyFunction, TExtra extends any[] = [boolean]> = (...args: [...Parameters<T>, ...TExtra]) => ReturnType<T>
6
5
 
@@ -94,7 +93,8 @@ export type TokenPropertyOperatorTypes =
94
93
 
95
94
  // export type EmptyObj = Record<"start"|"end", undefined>
96
95
  export type EmptyObj = Record<any, never>
97
- export type FirstConstructorParam<T extends new (...args: any) => any> = ConstructorParameters<T>["0"]
96
+ export type FirstParam<T extends AnyFunction> = Parameters<T>["0"]
97
+
98
98
 
99
99
  export type Position = {
100
100
  start: number
@@ -103,33 +103,198 @@ export type Position = {
103
103
 
104
104
  export enum AST_TYPE {
105
105
  EXPRESSION = "EXPRESSION",
106
+ NORMALIZED_EXPRESSION = "NORMALIZED_EXPRESSION",
106
107
  GROUP = "GROUP",
107
108
  ARRAY = "ARRAY",
108
109
  CONDITION = "CONDITION",
110
+ NORMALIZED_CONDITION = "NORMALIZED_CONDITION",
109
111
  VARIABLE = "VARIABLE",
110
112
  }
111
-
112
113
  // #region AST nodes
113
114
 
115
+
116
+ export type RawNode<T extends Node> = Omit<T, "valid" | "type" | "isNode">
117
+
118
+
119
+ /**
120
+ * The base type from which {@link ValidToken} and {@link ErrorToken} extend.
121
+ *
122
+ * Mostly for internal use, and I would suggest using {@link AnyToken} instead of this for typing things.
123
+ *
124
+ */
125
+ export interface BaseToken {
126
+ isToken: true
127
+ start: number
128
+ end: number
129
+ }
130
+ /**
131
+ * Valid tokens always have a value, even if it might be an empty string.
132
+ */
133
+ export interface ValidToken<TType extends TOKEN_TYPE = TOKEN_TYPE> extends BaseToken {
134
+ valid: true
135
+ type: TType
136
+ value: string
137
+ }
138
+ /**
139
+ * The type for invalid recovery tokens.
140
+ *
141
+ * Unlike valid tokens, error tokens:
142
+ *
143
+ * - Have no value.
144
+ *
145
+ * - Contain an extra property, `expected` with an array of tokens *that would have fixed the issue* (NOT every possible token that could be there).
146
+ *
147
+ * - The start end positions will always be equal. An invalid token has no length.
148
+ */
149
+ export interface ErrorToken extends BaseToken {
150
+ type?: undefined
151
+ value?: undefined
152
+ valid: false
153
+ expected: TOKEN_TYPE[]
154
+ }
155
+
114
156
  /**
115
157
  * For more easily typing tokens that might or might not be valid.
116
158
  *
117
- * Using @see Token does not work well in certain situations and is also more complex because it has so many generics.
159
+ * Using {@link Token} does not work well in certain situations and is also more complex because it has so many generics.
118
160
  */
119
161
  export type AnyToken<
120
162
  TType extends TOKEN_TYPE = TOKEN_TYPE,
121
163
  > =
122
164
  | ValidToken<TType>
123
- | ErrorToken<TType>
165
+ | ErrorToken
124
166
 
125
- export type ParserResults = ExpressionNode | ConditionNode | GroupNode | ErrorToken<TOKEN_TYPE.VALUE>
167
+ export type RawToken<T extends AnyToken> = Omit<T, "isToken" | "valid">
168
+
169
+ export type ParserResults = ExpressionNode | ConditionNode | GroupNode | ErrorToken
126
170
  /* eslint-disable @typescript-eslint/naming-convention */
127
171
 
128
172
 
173
+ /**
174
+ * The base AST type all node types extend from.
175
+ */
176
+
177
+ export interface Node<
178
+ TType extends AST_TYPE = AST_TYPE,
179
+ TValid extends boolean = boolean,
180
+ > {
181
+ isNode: true
182
+ type: TType
183
+ start: number
184
+ end: number
185
+ valid: TValid
186
+ }
187
+
188
+
189
+ /**
190
+ * A node that symbolizes a parenthesized expression (might be negated), and if `prefixableGroups` is enabled, a prefixed expression {@link ParserOptions} .
191
+ *
192
+ * ```txt
193
+ * (a || b)
194
+ * |----| ExpressionNode
195
+ * |------| GroupNode
196
+ *
197
+ * !(a || b)
198
+ * ^ prefix: "not" Token
199
+ * |----| ExpressionNode
200
+ * |-------| GroupNode
201
+ * ```
202
+ *
203
+ * If `prefixableGroups` is enabled:
204
+ * ```txt
205
+ * prefix(a || b)
206
+ * |----| prefix: ConditionNode
207
+ * |----| ExpressionNode
208
+ * |------------| GroupNode
209
+ *
210
+ * !prefix(a || b)
211
+ * |-----| prefix: ConditionNode
212
+ * |----| ExpressionNode
213
+ * |-------------| GroupNode
214
+ *
215
+ * !(a || b)
216
+ * ^ prefix: STILL a "not" Token
217
+ * ```
218
+ */
219
+ export interface GroupNode<
220
+ TValid extends boolean = boolean,
221
+ TPrefixable extends boolean = true,
222
+ TPrefix extends
223
+ TPrefixable extends true
224
+ ? ConditionNode<TValid> |
225
+ ValidToken<TOKEN_TYPE.NOT> |
226
+ undefined
227
+ : ValidToken<TOKEN_TYPE.NOT> |
228
+ undefined =
229
+ TPrefixable extends true
230
+ ? ConditionNode<TValid> |
231
+ ValidToken<TOKEN_TYPE.NOT> |
232
+ undefined
233
+ : ValidToken<TOKEN_TYPE.NOT>,
234
+ > extends Node<AST_TYPE.GROUP> {
235
+ /**
236
+ * If the condition is negated this will contain a "not" **token**, {@link ValidToken} .
237
+ *
238
+ * If `prefixableGroups` is enabled and the group is prefixed by a **condition**, this will be an {@link ConditionNode}.
239
+ *
240
+ * **Careful:** `!(a)` here this would not be a **condition** since it's just a regular negation.
241
+ *
242
+ * See examples at {@link GroupNode} .
243
+ */
244
+ prefix: TPrefix
245
+ expression:
246
+ | ConditionNode<TValid>
247
+ | GroupNode<TValid>
248
+ | ExpressionNode<TValid>
249
+ | (TValid extends false ? ErrorToken : never)
250
+ /**
251
+ * The parenthesis tokens, {@link ValidToken} . These will always be defined (although not necessarily with valid tokens).
252
+ */
253
+ paren: NodeDelimiters<TOKEN_TYPE.PARENL, TOKEN_TYPE.PARENR>
254
+ }
255
+
256
+
257
+ /**
258
+ * A variable represents **just** a string value (NOT it's boolean value).
259
+ *
260
+ * The parser will never return just a variable, they are always wrapped in an {@link ConditionNode} to give them a boolean value.
261
+ *
262
+ * A variable might or might not be quoted. If it is, the `quote` property will contain the quote tokens, see {@link ValidToken} . While they will always be of the same quote type, one might be valid while the other might not (see {@link ErrorToken}).
263
+ *
264
+ * `value` will contain the string value of the variable. The text is not processed and might still contain escaped characters (even if unquoted!) that need to be removed to get the intended value. This is so that the position of the node is accurate. {@link evaluate} will take care of unescaping when needed.
265
+ *
266
+ * If `prefixableStrings` is true, the `prefix` property might contain a value token.
267
+ */
268
+
269
+ export interface VariableNode<TValid extends boolean = boolean> extends Node<AST_TYPE.VARIABLE, TValid> {
270
+ value: TValid extends boolean
271
+ ? AnyToken<TOKEN_TYPE.VALUE>
272
+ : TValid extends true
273
+ ? ValidToken<TOKEN_TYPE.VALUE>
274
+ : ErrorToken
275
+ prefix?: ValidToken<TOKEN_TYPE.VALUE> // todo
276
+ quote?: NodeDelimiters<TokenQuoteTypes, TokenQuoteTypes>
277
+ }
278
+
279
+ export interface ExpressionNode<TValid extends boolean = boolean> extends Node<AST_TYPE.EXPRESSION> {
280
+ operator: AnyToken<TokenBooleanTypes>
281
+ left:
282
+ | ExpressionNode<TValid>
283
+ | ConditionNode<TValid>
284
+ | GroupNode<TValid>
285
+ | (TValid extends false ? ErrorToken : never)
286
+ right:
287
+ | ExpressionNode<TValid>
288
+ | ConditionNode<TValid>
289
+ | GroupNode<TValid>
290
+ | (TValid extends false ? ErrorToken : never)
291
+ }
292
+
293
+
129
294
  export type Nodes = ExpressionNode | ConditionNode | GroupNode | VariableNode | ArrayNode
130
295
 
131
296
  /**
132
- * Contains any delimiter tokens some AST nodes ( @see GroupNode and @see VariableNode ) can have.
297
+ * Contains any delimiter tokens some AST nodes ( {@link GroupNode} and {@link VariableNode} ) can have.
133
298
  *
134
299
  * These are usually not important for evaluating an expression but are useful for syntax highlighting.
135
300
  */
@@ -139,3 +304,123 @@ export type NodeDelimiters<TLEFT extends TOKEN_TYPE, TRIGHT extends TOKEN_TYPE =
139
304
  /** Only exists if regexes are enabled and this is a regex value. */
140
305
  flags?: ValidToken<TOKEN_TYPE.VALUE>
141
306
  }
307
+
308
+
309
+ export interface ArrayNode<TValid extends boolean = boolean> extends Node<AST_TYPE.ARRAY> {
310
+ values: VariableNode[]
311
+ bracket: NodeDelimiters<TOKEN_TYPE.BRACKETL, TOKEN_TYPE.BRACKETR>
312
+ valid: TValid
313
+ }
314
+
315
+
316
+ /**
317
+ * A condition is composed of a {@link Variable} , and, if it's negated, a "not" `operator` token, see {@link ValidToken}.
318
+ *
319
+ * The `value` property refers to the boolean value of the condition (not to the string value of the variable). See the `operator` property.
320
+ *
321
+ */
322
+ export interface ConditionNode<
323
+ TValid extends boolean = boolean,
324
+ > extends Node<AST_TYPE.CONDITION> {
325
+ /**
326
+ * Contains a value node which could be a variable, an array node (if enabled), or a group.
327
+ *
328
+ * Might be an error in cases like:
329
+ * - just passing a negation operator
330
+ * - if condition property operators are used and you have an input like just `[SEP]`, `op[SEP]`, `prop[SEP]op[SEP]`, `[CUSTOM OP]`, or `prop[CUSTOM OP]` where the variable is missing.
331
+ */
332
+ value:
333
+ | VariableNode<TValid>
334
+ | ArrayNode<TValid>
335
+ | GroupNode<TValid>
336
+ | (TValid extends false ? ErrorToken : never)
337
+ /**
338
+ * If the condition was negated, contains the "not" token, {@link ValidToken} , the condition was negated with.
339
+ */
340
+ operator?: ValidToken<TOKEN_TYPE.NOT>
341
+ /**
342
+ * If condition property operators are used, this will contain the property (as a variable), or an error token if it was missing (but some separator or operator was passed).
343
+ *
344
+ * While the property is a variable and can be a quoted variable, it cannot be a prefixed variable string.
345
+ *
346
+ * See the corresponding {@link ParserOptions} for more details.
347
+ */
348
+ property?: VariableNode | (TValid extends false ? ErrorToken : never)
349
+ /**
350
+ * If condition property operators are used, this will contain the operator.
351
+ *
352
+ * If a "short" form was used, this will contain an `OP_CUSTOM` type token, and the condition's `sep` will always be undefined.
353
+ *
354
+ * If a "long/expanded" form was used, this will contain a `VALUE` type token, and at least one of condition's `sep` tokens will be defined.
355
+ *
356
+ * See the corresponding {@link ParserOptions} for more details.
357
+ */
358
+ propertyOperator?: AnyToken<TOKEN_TYPE.OP_CUSTOM | TOKEN_TYPE.VALUE>
359
+ /**
360
+ * If "long/expanded" form condition property operators are used, this will contain the separators, otherwise it is undefined.
361
+ *
362
+ * If it's defined, either both side will be valid tokens, or only the left, while the right might be undefined or an error token.
363
+ *
364
+ * This is because given a string like `[SEP]val` which would produce an error like `[MISSING PROPERTY ERROR][SEP]var`, the separator is always interpreted as being the left one. And even if we have a situation like `op[SEP]var`, it is always interpreted by the parser as `prop[SEP]var`.
365
+ *
366
+ * Why might the right be undefined instead of an error token? This is because we don't need a separator between the operator and a group, `prop[SEP]op(group)`, but we do between a variable in cases like `prop[SEP]op"var"` which would produce an error token on the right side (we could parse this but it just looks inconsistent).
367
+ *
368
+ * See the corresponding {@link ParserOptions} for more details.
369
+ */
370
+ sep?: {
371
+ left?: AnyToken<TOKEN_TYPE.OP_EXPANDED_SEP>
372
+ right?: AnyToken<TOKEN_TYPE.OP_EXPANDED_SEP>
373
+ }
374
+ }
375
+
376
+ export interface NormalizedCondition<
377
+ TOp extends string = string,
378
+ TValue = any,
379
+ > {
380
+ type: AST_TYPE.NORMALIZED_CONDITION
381
+ value: TValue
382
+ operator?: TOp
383
+ property: string[]
384
+ negate: boolean
385
+ }
386
+
387
+
388
+ export interface NormalizedExpression<TType extends string = string, TValue = any> {
389
+ type: AST_TYPE.NORMALIZED_EXPRESSION
390
+ left:
391
+ | NormalizedExpression<TType, TValue>
392
+ | NormalizedCondition<TType, TValue>
393
+ right:
394
+ | NormalizedExpression<TType, TValue>
395
+ | NormalizedCondition<TType, TValue>
396
+ operator: TokenBooleanTypes
397
+ }
398
+
399
+ export type ParentTypes<T extends Node | BaseToken | undefined> =
400
+ T extends ValidToken
401
+ ?
402
+ | VariableNode
403
+ | GroupNode
404
+ | ExpressionNode
405
+ | ArrayNode
406
+ | ConditionNode
407
+ : T extends ErrorToken
408
+ ? VariableNode
409
+ | GroupNode
410
+ | ExpressionNode
411
+ | ArrayNode
412
+ | ConditionNode
413
+ : T extends GroupNode
414
+ ? ExpressionNode | GroupNode | undefined
415
+ : T extends VariableNode
416
+ ? ConditionNode | ArrayNode | undefined
417
+ : T extends ExpressionNode
418
+ ? GroupNode | ExpressionNode | undefined
419
+ : T extends ArrayNode
420
+ ? ConditionNode | undefined
421
+ : T extends ConditionNode | ExpressionNode
422
+ ? GroupNode | undefined
423
+ : T extends undefined
424
+ ? undefined
425
+ : never
426
+
@@ -1,15 +1,13 @@
1
- import type { AnyToken, Position } from "./ast.js"
2
-
3
- import type { ValidToken } from "../ast/classes/ValidToken.js"
1
+ import type { AnyToken, Position, ValidToken } from "./ast.js"
4
2
 
5
3
 
6
4
  /**
7
- * Contains information regarding the tokens around a cursor position. Mostly for internally use by @see autosuggest.
5
+ * Contains information regarding the tokens around a cursor position. Mostly for internally use by {@link autosuggest}.
8
6
  *
9
7
  * Notes:
10
8
  *
11
- * - There are no whitespace tokens because whitespace is not tokenized. `prev`, `at`, `next` properties that contain tokens are set looking only at the list of tokens extracted from the ast by @see extractTokens. This is why there is an extra `whitespace` property to tell us whether there is whitespace (i.e. a hole) between the cursor and the next/prev **valid** tokens or if it can't find any, the start/end of the input.
12
- * - If next/prev are invalid tokens, note that there are cases where more invalid tokens might follow them. To get them we can use @see getSurroundingErrors or we can just find their index in the tokens list and go forward/backward as needed:
9
+ * - There are no whitespace tokens because whitespace is not tokenized. `prev`, `at`, `next` properties that contain tokens are set looking only at the list of tokens extracted from the ast by {@link extractTokens}. This is why there is an extra `whitespace` property to tell us whether there is whitespace (i.e. a hole) between the cursor and the next/prev **valid** tokens or if it can't find any, the start/end of the input.
10
+ * - If next/prev are invalid tokens, note that there are cases where more invalid tokens might follow them. To get them we can use {@link getSurroundingErrors} or we can just find their index in the tokens list and go forward/backward as needed:
13
11
  * ```ts
14
12
  * let i = tokens.findIndex(t => t === info.next)
15
13
  * while (tokens[i] instanceof ErrorToken) {...}
@@ -115,7 +113,7 @@ export type Suggestion = {
115
113
  type: SUGGESTION_TYPE
116
114
  /** The range the suggestion should replace / be inserted at. */
117
115
  range: Position
118
- /** @see CursorInfo */
116
+ /** {@link CursorInfo} */
119
117
  cursorInfo: CursorInfo
120
118
  /** Tells us any additional requirements for inserting the suggestion. */
121
119
  requires: {
@@ -1,12 +1,7 @@
1
1
  import type { DeepRequired, MakeRequired } from "@alanscodelog/utils/types"
2
2
 
3
- import type { Position, TOKEN_TYPE } from "./ast.js"
3
+ import type { ArrayNode, ConditionNode, NormalizedCondition, Position, TOKEN_TYPE, ValidToken, VariableNode } from "./ast.js"
4
4
 
5
- import type { ArrayNode } from "../ast/classes/ArrayNode.js"
6
- import type { Condition } from "../ast/classes/Condition.js"
7
- import type { ConditionNode } from "../ast/classes/ConditionNode.js"
8
- import type { ValidToken } from "../ast/classes/ValidToken.js"
9
- import type { VariableNode } from "../ast/classes/VariableNode.js"
10
5
 
11
6
  // #partially-synced
12
7
  export type FullParserOptions<T extends {} = {}> = MakeRequired<
@@ -31,14 +26,14 @@ export type ParserOptions<T extends {} = {}> = {
31
26
  * ```js
32
27
  * category.subcategory.(variable1 || variable2 && !variable3)
33
28
  * ```
34
- * returns an @see GroupNode whose prefix is a value token with the value `category.subcategory.`
29
+ * returns an {@link GroupNode} whose prefix is a value token with the value `category.subcategory.`
35
30
  *
36
- * This prefix can later be applied by utility functions when evaluating the expression or extracting information from it. The default @see PrefixApplier appends the prefix name to every variable inside the group, so the above would expand into something like:
31
+ * This prefix can later be applied by utility functions when evaluating the expression or extracting information from it. The default {@link PrefixApplier} appends the prefix name to every variable inside the group, so the above would expand into something like:
37
32
  * ```js
38
33
  * category.subcategory.variable1 || category.subcategory.variable2 || !category.subcategory.variable3
39
34
  * ```
40
35
  *
41
- * @see UtilityOptions["prefixApplier"] for more examples and details on how to customize the behavior.
36
+ * {@link UtilityOptions}["prefixApplier"] for more examples and details on how to customize the behavior.
42
37
  */
43
38
  prefixableGroups?: boolean
44
39
  /**
@@ -61,11 +56,11 @@ export type ParserOptions<T extends {} = {}> = {
61
56
  * title:contains(value)
62
57
  * ```
63
58
  *
64
- * The information for these types of conditions are stored in a @see ConditionNode 's `property`, `propertyOperator`, and `sep` properties.
59
+ * The information for these types of conditions are stored in a {@link ConditionNode} 's `property`, `propertyOperator`, and `sep` properties.
65
60
  *
66
61
  * The separator can only be one character long and is added to the list of characters that need to be escaped.
67
62
  *
68
- * The property is always a @see VariableNode and can be a quoted variable, but it can never be a prefixed string (if using `prefixableStrings`).
63
+ * The property is always a {@link VariableNode} and can be a quoted variable, but it can never be a prefixed string (if using `prefixableStrings`).
69
64
  * ```
70
65
  */
71
66
  expandedPropertySeparator?: string
@@ -96,7 +91,7 @@ export type ParserOptions<T extends {} = {}> = {
96
91
  * title:(prefix(a OR B)) // title:prefix.a OR title:prefix.b
97
92
  * ```
98
93
  *
99
- * Like expanded property operators, these are stored in the @see ConditionNode 's `property`, `propertyOperator` properties. `sep` is not used, not even if the the same operator as the `expandedPropertySeparator` is used. This is what is meant by these types of operators taking priority. If used in this short style, it will always be interpreted as a `propertyOperator`.
94
+ * Like expanded property operators, these are stored in the {@link ConditionNode} 's `property`, `propertyOperator` properties. `sep` is not used, not even if the the same operator as the `expandedPropertySeparator` is used. This is what is meant by these types of operators taking priority. If used in this short style, it will always be interpreted as a `propertyOperator`.
100
95
  *
101
96
  */
102
97
  customPropertyOperators?: string[]
@@ -191,9 +186,9 @@ export type ParserOptions<T extends {} = {}> = {
191
186
  */
192
187
  keywords?: KeywordOptions
193
188
  /**
194
- * If prefixableGroups is true, this allows you to control how a prefix is applied for any methods that need to apply them (e.g. @see extractVariables @see evaluate).
189
+ * If prefixableGroups is true, this allows you to control how a prefix is applied for any methods that need to apply them (e.g. {@link extractVariables} {@link evaluate}).
195
190
  *
196
- * The default @see PrefixApplier function just appends the prefix.
191
+ * The default {@link PrefixApplier} function just appends the prefix.
197
192
  *
198
193
  * So for example:
199
194
  *
@@ -268,7 +263,7 @@ export type ParserOptions<T extends {} = {}> = {
268
263
  /**
269
264
  * When evaluating an ast against a context, this function determines whether a context value satisfies a condition.
270
265
  *
271
- * Given a partial {@link Condition} instance (negate property is not passed) and the contextValue (as extracted using {@link Condition.property}), it should return whether the values are equal.
266
+ * Given a partial {@link NormalizedCondition} instance (negate property is not passed) and the contextValue (as extracted using {@link NormalizedCondition.property}), it should return whether the values are equal.
272
267
  *
273
268
  * It is also passed the context itself for cases where there is no property and you might want to check the value against all properties of the context.
274
269
  *
@@ -293,7 +288,7 @@ export type ParserOptions<T extends {} = {}> = {
293
288
  /**
294
289
  * When {@link Parser.normalize normalizing} an ast, this function is needed to determine what exactly the value and operator of the condition is and whether it should be negated when evaluating.
295
290
  *
296
- * Given a query object it should return the values of the `value`, `operator`, and `negate` properties that will be assigned to {@link Condition}.
291
+ * Given a query object it should return the values of the `value`, `operator`, and `negate` properties that will be assigned to {@link NormalizedCondition}.
297
292
  *
298
293
  * You can think of the query object as a simplified version of the condition node. See {@link ValueQuery} for details on each property.
299
294
  *
@@ -348,7 +343,7 @@ export type ParserOptions<T extends {} = {}> = {
348
343
  */
349
344
  conditionNormalizer?: ConditionNormalizer
350
345
  /**
351
- * Similar to the valueComparer but for validating the ast before it's evaluated using @see Parser["validate"] (e.g. for syntax highlighting purposes). For the moment the ast must be valid (without syntax errors) to be validated.
346
+ * Similar to the valueComparer but for validating the ast before it's evaluated using {@link Parser}["validate"] (e.g. for syntax highlighting purposes). For the moment the ast must be valid (without syntax errors) to be validated.
352
347
  *
353
348
  * The only difference is nothing is actually evaluated (even though the values are available to the function\*) and the query contains the actual nodes/tokens for certain properties to make extracting positions easier.
354
349
  *
@@ -445,23 +440,23 @@ export type ValueQuery
445
440
  isExpanded: boolean
446
441
  }
447
442
 
448
- /** @see ParserOptions["valueValidator"] */
443
+ /** {@link ParserOptions}["valueValidator"] */
449
444
  export type ValidationQuery = Omit<ValueQuery, "value" | "operator" | "prefix" | "regexFlags" | "property"> & {
450
445
  value?: VariableNode | ArrayNode
451
446
  operator?: ValidToken<TOKEN_TYPE.VALUE | TOKEN_TYPE.OP_CUSTOM>
452
447
  prefix?: ValidToken<TOKEN_TYPE.VALUE>
453
448
  regexFlags?: ValidToken<TOKEN_TYPE.VALUE>
454
449
  property: VariableNode[]
455
- /** The property as would be passed to the @see ParserOptions["valueComparer"] function (i.e. joined as a string using the @see ParseOptions["prefixApplier"] ) */
450
+ /** The property as would be passed to the {@link ParserOptions}["valueComparer"] function (i.e. joined as a string using the {@link ParseOptions}["prefixApplier"] ) */
456
451
  propertyName?: string
457
- /** The property keys, as parsed by @see ParserOptions["keysParser"] */
452
+ /** The property keys, as parsed by {@link ParserOptions}["keysParser"] */
458
453
  propertyKeys: string[]
459
454
  /**
460
455
  * Contains a list of all the wrapping group prefix nodes.
461
456
  */
462
457
  prefixes?: VariableNode[]
463
458
  }
464
- export type ValueComparer = (condition: Omit<Condition, "negate">, contextValue: any, context: any) => boolean
459
+ export type ValueComparer = (condition: Omit<NormalizedCondition, "negate">, contextValue: any, context: any) => boolean
465
460
  export type ConditionNormalizer = (query: ValueQuery) => { value: any, operator: any, negate: boolean }
466
461
  export type ValueValidator<T = Record<string, any>> = (contextValue: any | undefined, query: ValidationQuery, context?: Record<string, any>) => (Position & T)[] | undefined | void
467
462
  // export type PrefixValidator<T> = (prefixes: VariableNode[], last: VariableNode) => (Position & T)[]
@@ -469,7 +464,7 @@ export type KeyParser = (key: string) => string[]
469
464
  export type PrefixApplier = (prefix: string, variable: string) => string
470
465
 
471
466
  export type KeywordEntry = {
472
- /** See @see ParserOptions["KeywordOptions"] */
467
+ /** See {@link ParserOptions}["KeywordOptions"] */
473
468
  isSymbol: boolean
474
469
  value: string
475
470
  }
@@ -1,31 +1,27 @@
1
1
  import { unreachable } from "@alanscodelog/utils/unreachable.js"
2
2
 
3
- import { ArrayNode } from "../ast/classes/ArrayNode.js"
4
- import { ConditionNode } from "../ast/classes/ConditionNode.js"
5
- import { ErrorToken } from "../ast/classes/ErrorToken.js"
6
- import { ExpressionNode } from "../ast/classes/ExpressionNode.js"
7
- import { GroupNode } from "../ast/classes/GroupNode.js"
8
- import { Node } from "../ast/classes/Node.js"
9
- import { VariableNode } from "../ast/classes/VariableNode.js"
10
- import type { AnyToken, AST_TYPE } from "../types/ast.js"
3
+ import { isNode } from "./isNode.js"
4
+ import { isToken } from "./isToken.js"
5
+
6
+ import { type AnyToken, AST_TYPE, type ErrorToken, type Nodes } from "../types/ast.js"
11
7
 
12
8
 
13
9
  /**
14
10
  * Extract a list of all the tokens (which might or might not be valid).
15
11
  */
16
- export function extractTokens(ast: Node<AST_TYPE> | ErrorToken): AnyToken[] {
17
- if (ast instanceof ErrorToken) {
12
+ export function extractTokens(ast: ErrorToken | Nodes): AnyToken[] {
13
+ if (isToken(ast) && !ast.valid) {
18
14
  return [ast]
19
15
  }
20
- if (ast instanceof VariableNode) {
16
+ if (ast.type === AST_TYPE.VARIABLE) {
21
17
  const prefix = ast.prefix ? [ast.prefix] : []
22
18
  const quoteR = ast.quote ? [ast.quote.right] : []
23
19
  const quoteL = ast.quote ? [ast.quote.left] : []
24
20
  const quoteFlags = ast.quote?.flags ? [ast.quote.flags] : []
25
21
  return [...prefix, ...quoteL, ast.value, ...quoteR, ...quoteFlags]
26
22
  }
27
- if (ast instanceof ConditionNode) {
28
- const value = ast.value instanceof Node
23
+ if (ast.type === AST_TYPE.CONDITION) {
24
+ const value = isNode(ast.value)
29
25
  ? extractTokens(ast.value)
30
26
  : [ast.value]
31
27
  const operator = ast.operator ? [ast.operator] : []
@@ -35,30 +31,30 @@ export function extractTokens(ast: Node<AST_TYPE> | ErrorToken): AnyToken[] {
35
31
  const sepR = ast.sep?.right ? [ast.sep.right] : []
36
32
  return [...operator, ...property, ...sepL, ...propertyOperator, ...sepR, ...value]
37
33
  }
38
- if (ast instanceof GroupNode) {
34
+ if (ast.type === AST_TYPE.GROUP) {
39
35
  const prefix = ast.prefix ?
40
- ast.prefix instanceof Node
36
+ isNode(ast.prefix)
41
37
  ? extractTokens(ast.prefix)
42
38
  : [ast.prefix]
43
39
  : []
44
40
  const parenL = ast.paren ? [ast.paren.left] : []
45
41
  const parenR = ast.paren ? [ast.paren.right] : []
46
- const expression = ast.expression instanceof Node
42
+ const expression = isNode(ast.expression)
47
43
  ? extractTokens(ast.expression)
48
44
  : [ast.expression]
49
45
  return [...prefix, ...parenL, ...expression, ...parenR]
50
46
  }
51
- if (ast instanceof ArrayNode) {
47
+ if (ast.type === AST_TYPE.ARRAY) {
52
48
  const values = ast.values.map(val => extractTokens(val))
53
49
  return [ast.bracket.left, ...values.flat(), ast.bracket.right]
54
50
  }
55
51
 
56
- if (ast instanceof ExpressionNode) {
57
- const right = ast.right instanceof Node
52
+ if (ast.type === AST_TYPE.EXPRESSION) {
53
+ const right = isNode(ast.right)
58
54
  ? extractTokens(ast.right)
59
55
  : [ast.right] as AnyToken[]
60
56
 
61
- const left = ast.left instanceof Node
57
+ const left = isNode(ast.left)
62
58
  ? extractTokens(ast.left)
63
59
  : [ast.left] as AnyToken[]
64
60
  return [...left, ast.operator, ...right]
@@ -0,0 +1,60 @@
1
+ import { type AddParameters } from "@alanscodelog/utils/types"
2
+
3
+ import { isNode } from "./isNode.js"
4
+
5
+ import { type AnyToken, AST_TYPE, type Nodes, } from "../types/ast.js"
6
+
7
+ /**
8
+ * Creates a map like Map<Node, Parent>, for easily accessing parents of nodes.
9
+ *
10
+ * This is done like this to avoid having circular structures in the ast.
11
+ *
12
+ * To get a properly typed parent, use {@link getParent} which you will need to pass a generated map.
13
+ */
14
+ export function generateParentsMap(ast: Nodes | AnyToken): Map<Nodes | AnyToken, Nodes> {
15
+ // eslint-disable-next-line prefer-rest-params
16
+ const recursiveMap = arguments[1] as Map<any, any>
17
+ const map = recursiveMap ?? new Map<any, any>()
18
+ const self: AddParameters<typeof generateParentsMap, [Map<any, any>]> = generateParentsMap
19
+ if (ast.type === AST_TYPE.VARIABLE) {
20
+ if (ast.prefix) map.set(ast.prefix, ast)
21
+ if (ast.quote?.left) map.set(ast.quote.left, ast)
22
+ if (ast.quote?.right) map.set(ast.quote.right, ast)
23
+ if (ast.quote?.flags) map.set(ast.quote.flags, ast)
24
+ map.set(ast.value, ast)
25
+ } else if (ast.type === AST_TYPE.CONDITION) {
26
+ if (ast.operator) map.set(ast.operator, ast)
27
+ if (ast.property) {
28
+ map.set(ast.property, ast)
29
+ if (isNode(ast.property)) self(ast.property, map)
30
+ }
31
+ if (ast.propertyOperator) map.set(ast.propertyOperator, ast)
32
+ if (ast.sep?.left) map.set(ast.sep.left, ast)
33
+ if (ast.sep?.right) map.set(ast.sep.right, ast)
34
+ map.set(ast.value, ast)
35
+ if (isNode(ast.value)) self(ast.value, map)
36
+ } else if (ast.type === AST_TYPE.EXPRESSION) {
37
+ if (ast.operator) map.set(ast.operator, ast)
38
+ map.set(ast.right, ast)
39
+ if (isNode(ast.right)) self(ast.right, map)
40
+ map.set(ast.left, ast)
41
+ if (isNode(ast.left)) self(ast.left, map)
42
+ } else if (ast.type === AST_TYPE.GROUP) {
43
+ if (ast.prefix) {
44
+ map.set(ast.prefix, ast)
45
+ if (isNode(ast.prefix)) self(ast.prefix, map)
46
+ }
47
+ if (ast.paren?.left) map.set(ast.paren.left, ast)
48
+ if (ast.paren?.right) map.set(ast.paren.right, ast)
49
+ map.set(ast.expression, ast)
50
+ if (isNode(ast.expression)) self(ast.expression, map)
51
+ } else if (ast.type === AST_TYPE.ARRAY) {
52
+ if (ast.bracket.left) map.set(ast.bracket.left, ast)
53
+ if (ast.bracket.right) map.set(ast.bracket.right, ast)
54
+ for (const val of ast.values) {
55
+ map.set(val, ast)
56
+ if (isNode(val)) self(val, map)
57
+ }
58
+ }
59
+ return map as any
60
+ }