reqon-dsl 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 (388) hide show
  1. package/.claude/settings.local.json +31 -0
  2. package/.claude/skills/api-integration.md +125 -0
  3. package/.claude/skills/database-schema.md +51 -0
  4. package/.claude/skills/dsl-design.md +80 -0
  5. package/.claude/skills/property-testing.md +143 -0
  6. package/.claude/skills/reqon/SKILL.md +44 -0
  7. package/.claude/skills/reqon/references/examples.md +206 -0
  8. package/.claude/skills/reqon/references/syntax.md +263 -0
  9. package/.claude/skills/vscode-extension.md +113 -0
  10. package/.github/dependabot.yml +32 -0
  11. package/.github/pull_request_template.md +21 -0
  12. package/.github/workflows/ci.yml +174 -0
  13. package/.github/workflows/release.yml +73 -0
  14. package/CLAUDE.md +72 -0
  15. package/CONTRIBUTING.md +161 -0
  16. package/README.md +235 -0
  17. package/TODO.md +51 -0
  18. package/dist/ast/index.d.ts +1 -0
  19. package/dist/ast/index.js +1 -0
  20. package/dist/ast/nodes.d.ts +237 -0
  21. package/dist/ast/nodes.js +12 -0
  22. package/dist/auth/auth.test.d.ts +1 -0
  23. package/dist/auth/auth.test.js +255 -0
  24. package/dist/auth/circuit-breaker.d.ts +115 -0
  25. package/dist/auth/circuit-breaker.js +267 -0
  26. package/dist/auth/credentials.d.ts +91 -0
  27. package/dist/auth/credentials.js +169 -0
  28. package/dist/auth/index.d.ts +5 -0
  29. package/dist/auth/index.js +8 -0
  30. package/dist/auth/oauth2-provider.d.ts +41 -0
  31. package/dist/auth/oauth2-provider.js +131 -0
  32. package/dist/auth/rate-limiter.d.ts +61 -0
  33. package/dist/auth/rate-limiter.js +380 -0
  34. package/dist/auth/token-store.d.ts +30 -0
  35. package/dist/auth/token-store.js +148 -0
  36. package/dist/auth/types.d.ts +142 -0
  37. package/dist/auth/types.js +1 -0
  38. package/dist/cli.d.ts +2 -0
  39. package/dist/cli.js +270 -0
  40. package/dist/errors/errors.test.d.ts +1 -0
  41. package/dist/errors/errors.test.js +165 -0
  42. package/dist/errors/index.d.ts +83 -0
  43. package/dist/errors/index.js +159 -0
  44. package/dist/execution/execution.test.d.ts +1 -0
  45. package/dist/execution/execution.test.js +246 -0
  46. package/dist/execution/index.d.ts +4 -0
  47. package/dist/execution/index.js +2 -0
  48. package/dist/execution/state.d.ts +136 -0
  49. package/dist/execution/state.js +82 -0
  50. package/dist/execution/store.d.ts +52 -0
  51. package/dist/execution/store.js +120 -0
  52. package/dist/index.d.ts +27 -0
  53. package/dist/index.js +57 -0
  54. package/dist/integration.test.d.ts +1 -0
  55. package/dist/integration.test.js +168 -0
  56. package/dist/interpreter/context.d.ts +15 -0
  57. package/dist/interpreter/context.js +29 -0
  58. package/dist/interpreter/evaluator.d.ts +5 -0
  59. package/dist/interpreter/evaluator.js +223 -0
  60. package/dist/interpreter/evaluator.test.d.ts +1 -0
  61. package/dist/interpreter/evaluator.test.js +512 -0
  62. package/dist/interpreter/executor.d.ts +131 -0
  63. package/dist/interpreter/executor.js +663 -0
  64. package/dist/interpreter/fetch-handler.d.ts +43 -0
  65. package/dist/interpreter/fetch-handler.js +203 -0
  66. package/dist/interpreter/http.d.ts +57 -0
  67. package/dist/interpreter/http.js +210 -0
  68. package/dist/interpreter/http.test.d.ts +1 -0
  69. package/dist/interpreter/http.test.js +299 -0
  70. package/dist/interpreter/index.d.ts +7 -0
  71. package/dist/interpreter/index.js +7 -0
  72. package/dist/interpreter/pagination.d.ts +63 -0
  73. package/dist/interpreter/pagination.js +155 -0
  74. package/dist/interpreter/progress.test.d.ts +1 -0
  75. package/dist/interpreter/progress.test.js +216 -0
  76. package/dist/interpreter/schema-matcher.d.ts +16 -0
  77. package/dist/interpreter/schema-matcher.js +136 -0
  78. package/dist/interpreter/schema-matcher.test.d.ts +1 -0
  79. package/dist/interpreter/schema-matcher.test.js +122 -0
  80. package/dist/interpreter/signals.d.ts +57 -0
  81. package/dist/interpreter/signals.js +73 -0
  82. package/dist/interpreter/step-handlers/for-handler.d.ts +17 -0
  83. package/dist/interpreter/step-handlers/for-handler.js +51 -0
  84. package/dist/interpreter/step-handlers/index.d.ts +8 -0
  85. package/dist/interpreter/step-handlers/index.js +8 -0
  86. package/dist/interpreter/step-handlers/map-handler.d.ts +10 -0
  87. package/dist/interpreter/step-handlers/map-handler.js +20 -0
  88. package/dist/interpreter/step-handlers/match-handler.d.ts +27 -0
  89. package/dist/interpreter/step-handlers/match-handler.js +61 -0
  90. package/dist/interpreter/step-handlers/store-handler.d.ts +13 -0
  91. package/dist/interpreter/step-handlers/store-handler.js +66 -0
  92. package/dist/interpreter/step-handlers/types.d.ts +15 -0
  93. package/dist/interpreter/step-handlers/types.js +1 -0
  94. package/dist/interpreter/step-handlers/validate-handler.d.ts +10 -0
  95. package/dist/interpreter/step-handlers/validate-handler.js +26 -0
  96. package/dist/interpreter/step-handlers/webhook-handler.d.ts +36 -0
  97. package/dist/interpreter/step-handlers/webhook-handler.js +104 -0
  98. package/dist/lexer/index.d.ts +10 -0
  99. package/dist/lexer/index.js +12 -0
  100. package/dist/lexer/lexer.d.ts +24 -0
  101. package/dist/lexer/lexer.js +264 -0
  102. package/dist/lexer/lexer.test.d.ts +1 -0
  103. package/dist/lexer/lexer.test.js +259 -0
  104. package/dist/lexer/tokens.d.ts +69 -0
  105. package/dist/lexer/tokens.js +146 -0
  106. package/dist/loader/index.d.ts +36 -0
  107. package/dist/loader/index.js +220 -0
  108. package/dist/loader/loader.test.d.ts +1 -0
  109. package/dist/loader/loader.test.js +287 -0
  110. package/dist/oas/index.d.ts +4 -0
  111. package/dist/oas/index.js +2 -0
  112. package/dist/oas/loader.d.ts +21 -0
  113. package/dist/oas/loader.js +82 -0
  114. package/dist/oas/oas.test.d.ts +1 -0
  115. package/dist/oas/oas.test.js +218 -0
  116. package/dist/oas/validator.d.ts +12 -0
  117. package/dist/oas/validator.js +227 -0
  118. package/dist/parser/base.d.ts +33 -0
  119. package/dist/parser/base.js +97 -0
  120. package/dist/parser/expressions.d.ts +27 -0
  121. package/dist/parser/expressions.js +248 -0
  122. package/dist/parser/expressions.test.d.ts +1 -0
  123. package/dist/parser/expressions.test.js +378 -0
  124. package/dist/parser/index.d.ts +3 -0
  125. package/dist/parser/index.js +3 -0
  126. package/dist/parser/match.test.d.ts +1 -0
  127. package/dist/parser/match.test.js +254 -0
  128. package/dist/parser/parser.d.ts +68 -0
  129. package/dist/parser/parser.js +1229 -0
  130. package/dist/parser/parser.test.d.ts +1 -0
  131. package/dist/parser/parser.test.js +333 -0
  132. package/dist/parser/schedule.test.d.ts +1 -0
  133. package/dist/parser/schedule.test.js +241 -0
  134. package/dist/plugin.d.ts +35 -0
  135. package/dist/plugin.js +68 -0
  136. package/dist/scheduler/cron-parser.d.ts +32 -0
  137. package/dist/scheduler/cron-parser.js +198 -0
  138. package/dist/scheduler/cron-parser.test.d.ts +1 -0
  139. package/dist/scheduler/cron-parser.test.js +188 -0
  140. package/dist/scheduler/index.d.ts +3 -0
  141. package/dist/scheduler/index.js +2 -0
  142. package/dist/scheduler/scheduler.d.ts +81 -0
  143. package/dist/scheduler/scheduler.js +376 -0
  144. package/dist/scheduler/types.d.ts +65 -0
  145. package/dist/scheduler/types.js +1 -0
  146. package/dist/stores/factory.d.ts +36 -0
  147. package/dist/stores/factory.js +73 -0
  148. package/dist/stores/file.d.ts +60 -0
  149. package/dist/stores/file.js +173 -0
  150. package/dist/stores/file.test.d.ts +1 -0
  151. package/dist/stores/file.test.js +165 -0
  152. package/dist/stores/index.d.ts +6 -0
  153. package/dist/stores/index.js +5 -0
  154. package/dist/stores/memory.d.ts +19 -0
  155. package/dist/stores/memory.js +51 -0
  156. package/dist/stores/memory.test.d.ts +1 -0
  157. package/dist/stores/memory.test.js +157 -0
  158. package/dist/stores/postgrest.d.ts +55 -0
  159. package/dist/stores/postgrest.js +217 -0
  160. package/dist/stores/stores.test.d.ts +1 -0
  161. package/dist/stores/stores.test.js +158 -0
  162. package/dist/stores/types.d.ts +31 -0
  163. package/dist/stores/types.js +26 -0
  164. package/dist/sync/index.d.ts +4 -0
  165. package/dist/sync/index.js +2 -0
  166. package/dist/sync/state.d.ts +69 -0
  167. package/dist/sync/state.js +66 -0
  168. package/dist/sync/store.d.ts +49 -0
  169. package/dist/sync/store.js +93 -0
  170. package/dist/sync/sync.test.d.ts +1 -0
  171. package/dist/sync/sync.test.js +221 -0
  172. package/dist/utils/async.d.ts +7 -0
  173. package/dist/utils/async.js +9 -0
  174. package/dist/utils/file.d.ts +38 -0
  175. package/dist/utils/file.js +92 -0
  176. package/dist/utils/index.d.ts +4 -0
  177. package/dist/utils/index.js +4 -0
  178. package/dist/utils/logger.d.ts +34 -0
  179. package/dist/utils/logger.js +39 -0
  180. package/dist/utils/path.d.ts +12 -0
  181. package/dist/utils/path.js +41 -0
  182. package/dist/webhook/index.d.ts +8 -0
  183. package/dist/webhook/index.js +7 -0
  184. package/dist/webhook/server.d.ts +84 -0
  185. package/dist/webhook/server.js +319 -0
  186. package/dist/webhook/store.d.ts +67 -0
  187. package/dist/webhook/store.js +193 -0
  188. package/dist/webhook/types.d.ts +88 -0
  189. package/dist/webhook/types.js +6 -0
  190. package/docusaurus/README.md +41 -0
  191. package/docusaurus/docs/advanced/execution-state.md +283 -0
  192. package/docusaurus/docs/advanced/extending-reqon.md +388 -0
  193. package/docusaurus/docs/advanced/multi-file-missions.md +250 -0
  194. package/docusaurus/docs/advanced/parallel-execution.md +353 -0
  195. package/docusaurus/docs/api-reference.md +443 -0
  196. package/docusaurus/docs/authentication/api-key.md +339 -0
  197. package/docusaurus/docs/authentication/basic.md +276 -0
  198. package/docusaurus/docs/authentication/bearer.md +282 -0
  199. package/docusaurus/docs/authentication/oauth2.md +317 -0
  200. package/docusaurus/docs/authentication/overview.md +251 -0
  201. package/docusaurus/docs/cli.md +229 -0
  202. package/docusaurus/docs/core-concepts/actions.md +286 -0
  203. package/docusaurus/docs/core-concepts/missions.md +264 -0
  204. package/docusaurus/docs/core-concepts/schemas.md +353 -0
  205. package/docusaurus/docs/core-concepts/sources.md +339 -0
  206. package/docusaurus/docs/core-concepts/stores.md +332 -0
  207. package/docusaurus/docs/dsl-syntax/expressions.md +361 -0
  208. package/docusaurus/docs/dsl-syntax/fetch.md +293 -0
  209. package/docusaurus/docs/dsl-syntax/for-loops.md +324 -0
  210. package/docusaurus/docs/dsl-syntax/map.md +345 -0
  211. package/docusaurus/docs/dsl-syntax/match.md +387 -0
  212. package/docusaurus/docs/dsl-syntax/pipelines.md +397 -0
  213. package/docusaurus/docs/dsl-syntax/validate.md +401 -0
  214. package/docusaurus/docs/error-handling/dead-letter-queues.md +399 -0
  215. package/docusaurus/docs/error-handling/flow-control.md +337 -0
  216. package/docusaurus/docs/error-handling/retry-strategies.md +368 -0
  217. package/docusaurus/docs/examples.md +488 -0
  218. package/docusaurus/docs/getting-started.md +256 -0
  219. package/docusaurus/docs/http/circuit-breaker.md +401 -0
  220. package/docusaurus/docs/http/incremental-sync.md +394 -0
  221. package/docusaurus/docs/http/pagination.md +361 -0
  222. package/docusaurus/docs/http/rate-limiting.md +383 -0
  223. package/docusaurus/docs/http/requests.md +328 -0
  224. package/docusaurus/docs/http/retry.md +402 -0
  225. package/docusaurus/docs/intro.md +90 -0
  226. package/docusaurus/docs/openapi/loading-specs.md +305 -0
  227. package/docusaurus/docs/openapi/operation-calls.md +314 -0
  228. package/docusaurus/docs/openapi/overview.md +212 -0
  229. package/docusaurus/docs/openapi/response-validation.md +344 -0
  230. package/docusaurus/docs/scheduling/cron.md +305 -0
  231. package/docusaurus/docs/scheduling/daemon-mode.md +317 -0
  232. package/docusaurus/docs/scheduling/intervals.md +289 -0
  233. package/docusaurus/docs/scheduling/overview.md +231 -0
  234. package/docusaurus/docs/stores/custom-adapters.md +376 -0
  235. package/docusaurus/docs/stores/file.md +236 -0
  236. package/docusaurus/docs/stores/memory.md +193 -0
  237. package/docusaurus/docs/stores/overview.md +274 -0
  238. package/docusaurus/docs/stores/postgrest.md +316 -0
  239. package/docusaurus/docusaurus.config.ts +148 -0
  240. package/docusaurus/package-lock.json +18029 -0
  241. package/docusaurus/package.json +47 -0
  242. package/docusaurus/sidebars.ts +155 -0
  243. package/docusaurus/src/components/HomepageFeatures/index.tsx +105 -0
  244. package/docusaurus/src/components/HomepageFeatures/styles.module.css +12 -0
  245. package/docusaurus/src/css/custom.css +169 -0
  246. package/docusaurus/src/pages/index.module.css +48 -0
  247. package/docusaurus/src/pages/index.tsx +110 -0
  248. package/docusaurus/src/pages/markdown-page.md +7 -0
  249. package/docusaurus/static/.nojekyll +0 -0
  250. package/docusaurus/static/img/docusaurus-social-card.jpg +0 -0
  251. package/docusaurus/static/img/docusaurus.png +0 -0
  252. package/docusaurus/static/img/favicon.ico +0 -0
  253. package/docusaurus/static/img/logo.svg +10 -0
  254. package/docusaurus/static/img/undraw_docusaurus_mountain.svg +171 -0
  255. package/docusaurus/static/img/undraw_docusaurus_react.svg +170 -0
  256. package/docusaurus/static/img/undraw_docusaurus_tree.svg +40 -0
  257. package/docusaurus/tsconfig.json +8 -0
  258. package/examples/README.md +112 -0
  259. package/examples/error-handling/README.md +150 -0
  260. package/examples/error-handling/payment-processor.vague +287 -0
  261. package/examples/github-sync/README.md +74 -0
  262. package/examples/github-sync/fetch-issues.vague +47 -0
  263. package/examples/github-sync/fetch-prs.vague +40 -0
  264. package/examples/github-sync/mission.vague +101 -0
  265. package/examples/github-sync/normalize.vague +70 -0
  266. package/examples/jsonplaceholder/README.md +28 -0
  267. package/examples/jsonplaceholder/posts.vague +48 -0
  268. package/examples/petstore/README.md +35 -0
  269. package/examples/petstore/openapi.yaml +97 -0
  270. package/examples/petstore/sync.vague +52 -0
  271. package/examples/temporal-comparison/README.md +297 -0
  272. package/examples/temporal-comparison/reconciliation.vague +355 -0
  273. package/examples/temporal-comparison/temporal/activities/index.ts +8 -0
  274. package/examples/temporal-comparison/temporal/activities/shipstation.ts +225 -0
  275. package/examples/temporal-comparison/temporal/activities/shopify.ts +257 -0
  276. package/examples/temporal-comparison/temporal/activities/storage.ts +198 -0
  277. package/examples/temporal-comparison/temporal/activities/stripe.ts +169 -0
  278. package/examples/temporal-comparison/temporal/activities/validation.ts +205 -0
  279. package/examples/temporal-comparison/temporal/client/schedule.ts +218 -0
  280. package/examples/temporal-comparison/temporal/config/retry.ts +63 -0
  281. package/examples/temporal-comparison/temporal/types/index.ts +129 -0
  282. package/examples/temporal-comparison/temporal/workers/main.ts +130 -0
  283. package/examples/temporal-comparison/temporal/workflows/orderReconciliation.ts +262 -0
  284. package/examples/xero/README.md +88 -0
  285. package/examples/xero/invoices.vague +189 -0
  286. package/package.json +40 -0
  287. package/src/api-integration.test.ts +954 -0
  288. package/src/ast/index.ts +1 -0
  289. package/src/ast/nodes.ts +310 -0
  290. package/src/auth/auth.test.ts +326 -0
  291. package/src/auth/circuit-breaker.test.ts +390 -0
  292. package/src/auth/circuit-breaker.ts +379 -0
  293. package/src/auth/credentials.test.ts +273 -0
  294. package/src/auth/credentials.ts +246 -0
  295. package/src/auth/index.ts +40 -0
  296. package/src/auth/oauth2-provider.ts +177 -0
  297. package/src/auth/rate-limiter.ts +459 -0
  298. package/src/auth/token-store.ts +177 -0
  299. package/src/auth/types.ts +159 -0
  300. package/src/benchmark/e2e.bench.ts +288 -0
  301. package/src/benchmark/evaluator.bench.ts +331 -0
  302. package/src/benchmark/fixtures.ts +295 -0
  303. package/src/benchmark/index.ts +108 -0
  304. package/src/benchmark/lexer.bench.ts +69 -0
  305. package/src/benchmark/parser.bench.ts +103 -0
  306. package/src/benchmark/resilience.bench.ts +193 -0
  307. package/src/benchmark/store.bench.ts +147 -0
  308. package/src/benchmark/utils.ts +230 -0
  309. package/src/cli.ts +313 -0
  310. package/src/errors/errors.test.ts +234 -0
  311. package/src/errors/index.ts +223 -0
  312. package/src/execution/execution.test.ts +307 -0
  313. package/src/execution/index.ts +21 -0
  314. package/src/execution/state.ts +207 -0
  315. package/src/execution/store.ts +188 -0
  316. package/src/index.ts +169 -0
  317. package/src/integration.test.ts +192 -0
  318. package/src/interpreter/context.ts +57 -0
  319. package/src/interpreter/evaluator.test.ts +796 -0
  320. package/src/interpreter/evaluator.ts +245 -0
  321. package/src/interpreter/executor.ts +946 -0
  322. package/src/interpreter/fetch-handler.ts +302 -0
  323. package/src/interpreter/http.test.ts +423 -0
  324. package/src/interpreter/http.ts +308 -0
  325. package/src/interpreter/index.ts +32 -0
  326. package/src/interpreter/pagination.ts +207 -0
  327. package/src/interpreter/progress.test.ts +276 -0
  328. package/src/interpreter/schema-matcher.test.ts +160 -0
  329. package/src/interpreter/schema-matcher.ts +168 -0
  330. package/src/interpreter/signals.ts +73 -0
  331. package/src/interpreter/step-handlers/for-handler.ts +65 -0
  332. package/src/interpreter/step-handlers/index.ts +17 -0
  333. package/src/interpreter/step-handlers/map-handler.ts +24 -0
  334. package/src/interpreter/step-handlers/match-handler.ts +101 -0
  335. package/src/interpreter/step-handlers/store-handler.ts +78 -0
  336. package/src/interpreter/step-handlers/types.ts +17 -0
  337. package/src/interpreter/step-handlers/validate-handler.ts +30 -0
  338. package/src/interpreter/step-handlers/webhook-handler.ts +142 -0
  339. package/src/lexer/index.ts +18 -0
  340. package/src/lexer/lexer.test.ts +316 -0
  341. package/src/lexer/tokens.ts +179 -0
  342. package/src/loader/index.ts +288 -0
  343. package/src/loader/loader.test.ts +360 -0
  344. package/src/oas/index.ts +4 -0
  345. package/src/oas/loader.ts +126 -0
  346. package/src/oas/oas.test.ts +254 -0
  347. package/src/oas/validator.ts +299 -0
  348. package/src/parser/base.ts +124 -0
  349. package/src/parser/expressions.test.ts +525 -0
  350. package/src/parser/expressions.ts +314 -0
  351. package/src/parser/index.ts +3 -0
  352. package/src/parser/match.test.ts +296 -0
  353. package/src/parser/parser.test.ts +739 -0
  354. package/src/parser/parser.ts +1469 -0
  355. package/src/parser/schedule.test.ts +287 -0
  356. package/src/parser/webhook.test.ts +248 -0
  357. package/src/plugin.ts +83 -0
  358. package/src/scheduler/cron-parser.test.ts +236 -0
  359. package/src/scheduler/cron-parser.ts +236 -0
  360. package/src/scheduler/index.ts +10 -0
  361. package/src/scheduler/scheduler.ts +443 -0
  362. package/src/scheduler/types.ts +71 -0
  363. package/src/stores/factory.ts +104 -0
  364. package/src/stores/file.test.ts +276 -0
  365. package/src/stores/file.ts +211 -0
  366. package/src/stores/index.ts +6 -0
  367. package/src/stores/memory.test.ts +238 -0
  368. package/src/stores/memory.ts +63 -0
  369. package/src/stores/postgrest.test.ts +488 -0
  370. package/src/stores/postgrest.ts +263 -0
  371. package/src/stores/stores.test.ts +197 -0
  372. package/src/stores/types.ts +58 -0
  373. package/src/sync/index.ts +16 -0
  374. package/src/sync/state.ts +126 -0
  375. package/src/sync/store.ts +139 -0
  376. package/src/sync/sync.test.ts +271 -0
  377. package/src/utils/async.ts +10 -0
  378. package/src/utils/file.ts +106 -0
  379. package/src/utils/index.ts +14 -0
  380. package/src/utils/logger.ts +53 -0
  381. package/src/utils/path.ts +47 -0
  382. package/src/webhook/index.ts +15 -0
  383. package/src/webhook/server.test.ts +253 -0
  384. package/src/webhook/server.ts +389 -0
  385. package/src/webhook/store.ts +239 -0
  386. package/src/webhook/types.ts +93 -0
  387. package/tsconfig.json +17 -0
  388. package/vitest.config.ts +39 -0
@@ -0,0 +1,316 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { Lexer as ReqonLexer, TokenType, type Token } from './index.js';
3
+ import { ReqonTokenType } from './tokens.js';
4
+
5
+ describe('ReqonLexer', () => {
6
+ describe('string tokenization', () => {
7
+ it('tokenizes simple strings', () => {
8
+ const lexer = new ReqonLexer('"hello world"');
9
+ const tokens = lexer.tokenize();
10
+
11
+ expect(tokens[0].type).toBe(TokenType.STRING);
12
+ expect(tokens[0].value).toBe('hello world');
13
+ });
14
+
15
+ it('handles escape sequences', () => {
16
+ const lexer = new ReqonLexer('"line1\\nline2"');
17
+ const tokens = lexer.tokenize();
18
+
19
+ expect(tokens[0].type).toBe(TokenType.STRING);
20
+ expect(tokens[0].value).toBe('line1\nline2');
21
+ });
22
+
23
+ it('handles tab escape sequence', () => {
24
+ const lexer = new ReqonLexer('"col1\\tcol2"');
25
+ const tokens = lexer.tokenize();
26
+
27
+ expect(tokens[0].value).toBe('col1\tcol2');
28
+ });
29
+
30
+ it('handles escaped quotes', () => {
31
+ const lexer = new ReqonLexer('"say \\"hello\\""');
32
+ const tokens = lexer.tokenize();
33
+
34
+ expect(tokens[0].value).toBe('say "hello"');
35
+ });
36
+
37
+ it('handles escaped backslash', () => {
38
+ const lexer = new ReqonLexer('"path\\\\to\\\\file"');
39
+ const tokens = lexer.tokenize();
40
+
41
+ expect(tokens[0].value).toBe('path\\to\\file');
42
+ });
43
+
44
+ it('throws on unterminated string', () => {
45
+ const lexer = new ReqonLexer('"unterminated');
46
+
47
+ expect(() => lexer.tokenize()).toThrow('Unterminated string');
48
+ });
49
+ });
50
+
51
+ describe('number tokenization', () => {
52
+ it('tokenizes integers', () => {
53
+ const lexer = new ReqonLexer('42');
54
+ const tokens = lexer.tokenize();
55
+
56
+ expect(tokens[0].type).toBe(TokenType.NUMBER);
57
+ expect(tokens[0].value).toBe('42');
58
+ });
59
+
60
+ it('tokenizes decimals', () => {
61
+ const lexer = new ReqonLexer('3.14159');
62
+ const tokens = lexer.tokenize();
63
+
64
+ expect(tokens[0].type).toBe(TokenType.NUMBER);
65
+ expect(tokens[0].value).toBe('3.14159');
66
+ });
67
+
68
+ it('tokenizes numbers with leading zero', () => {
69
+ const lexer = new ReqonLexer('0.5');
70
+ const tokens = lexer.tokenize();
71
+
72
+ expect(tokens[0].type).toBe(TokenType.NUMBER);
73
+ expect(tokens[0].value).toBe('0.5');
74
+ });
75
+ });
76
+
77
+ describe('keyword tokenization', () => {
78
+ it('recognizes Reqon keywords', () => {
79
+ const lexer = new ReqonLexer('mission action source store call run');
80
+ const tokens = lexer.tokenize();
81
+
82
+ expect(tokens[0].type).toBe(ReqonTokenType.MISSION);
83
+ expect(tokens[1].type).toBe(ReqonTokenType.ACTION);
84
+ expect(tokens[2].type).toBe(ReqonTokenType.SOURCE);
85
+ expect(tokens[3].type).toBe(ReqonTokenType.STORE);
86
+ expect(tokens[4].type).toBe(ReqonTokenType.CALL);
87
+ expect(tokens[5].type).toBe(ReqonTokenType.RUN);
88
+ });
89
+
90
+ it('recognizes HTTP method keywords', () => {
91
+ const lexer = new ReqonLexer('GET POST PUT PATCH DELETE');
92
+ const tokens = lexer.tokenize();
93
+
94
+ expect(tokens[0].type).toBe(ReqonTokenType.GET);
95
+ expect(tokens[1].type).toBe(ReqonTokenType.POST);
96
+ expect(tokens[2].type).toBe(ReqonTokenType.PUT);
97
+ expect(tokens[3].type).toBe(ReqonTokenType.PATCH);
98
+ expect(tokens[4].type).toBe(ReqonTokenType.DELETE);
99
+ });
100
+
101
+ it('recognizes auth type keywords', () => {
102
+ const lexer = new ReqonLexer('oauth2 bearer basic api_key');
103
+ const tokens = lexer.tokenize();
104
+
105
+ expect(tokens[0].type).toBe(ReqonTokenType.OAUTH2);
106
+ expect(tokens[1].type).toBe(ReqonTokenType.BEARER);
107
+ expect(tokens[2].type).toBe(ReqonTokenType.BASIC);
108
+ expect(tokens[3].type).toBe(ReqonTokenType.API_KEY);
109
+ });
110
+
111
+ it('recognizes Vague keywords', () => {
112
+ const lexer = new ReqonLexer('match where and or not true false null');
113
+ const tokens = lexer.tokenize();
114
+
115
+ expect(tokens[0].type).toBe(TokenType.MATCH);
116
+ expect(tokens[1].type).toBe(TokenType.WHERE);
117
+ expect(tokens[2].type).toBe(TokenType.AND);
118
+ expect(tokens[3].type).toBe(TokenType.OR);
119
+ expect(tokens[4].type).toBe(TokenType.NOT);
120
+ expect(tokens[5].type).toBe(TokenType.TRUE);
121
+ expect(tokens[6].type).toBe(TokenType.FALSE);
122
+ expect(tokens[7].type).toBe(TokenType.NULL);
123
+ });
124
+
125
+ it('treats unknown words as identifiers', () => {
126
+ const lexer = new ReqonLexer('myVariable anotherOne');
127
+ const tokens = lexer.tokenize();
128
+
129
+ expect(tokens[0].type).toBe(TokenType.IDENTIFIER);
130
+ expect(tokens[0].value).toBe('myVariable');
131
+ expect(tokens[1].type).toBe(TokenType.IDENTIFIER);
132
+ expect(tokens[1].value).toBe('anotherOne');
133
+ });
134
+ });
135
+
136
+ describe('operator tokenization', () => {
137
+ it('recognizes right arrow operator', () => {
138
+ const lexer = new ReqonLexer('map item -> Output');
139
+ const tokens = lexer.tokenize();
140
+
141
+ expect(tokens[0].type).toBe(ReqonTokenType.MAP);
142
+ expect(tokens[1].type).toBe(TokenType.IDENTIFIER);
143
+ expect(tokens[2].type).toBe(TokenType.RIGHT_ARROW);
144
+ expect(tokens[3].type).toBe(TokenType.IDENTIFIER);
145
+ });
146
+
147
+ it('recognizes two-character operators', () => {
148
+ const lexer = new ReqonLexer('== <= >= => ..');
149
+ const tokens = lexer.tokenize();
150
+
151
+ expect(tokens[0].type).toBe(TokenType.DOUBLE_EQUALS);
152
+ expect(tokens[1].type).toBe(TokenType.LTE);
153
+ expect(tokens[2].type).toBe(TokenType.GTE);
154
+ expect(tokens[3].type).toBe(TokenType.ARROW);
155
+ expect(tokens[4].type).toBe(TokenType.DOTDOT);
156
+ });
157
+
158
+ it('recognizes single-character operators', () => {
159
+ const lexer = new ReqonLexer('+ - * / : = < > . , ( ) { } [ ]');
160
+ const tokens = lexer.tokenize();
161
+
162
+ expect(tokens[0].type).toBe(TokenType.PLUS);
163
+ expect(tokens[1].type).toBe(TokenType.MINUS);
164
+ expect(tokens[2].type).toBe(TokenType.STAR);
165
+ expect(tokens[3].type).toBe(TokenType.SLASH);
166
+ expect(tokens[4].type).toBe(TokenType.COLON);
167
+ expect(tokens[5].type).toBe(TokenType.EQUALS);
168
+ expect(tokens[6].type).toBe(TokenType.LT);
169
+ expect(tokens[7].type).toBe(TokenType.GT);
170
+ expect(tokens[8].type).toBe(TokenType.DOT);
171
+ expect(tokens[9].type).toBe(TokenType.COMMA);
172
+ expect(tokens[10].type).toBe(TokenType.LPAREN);
173
+ expect(tokens[11].type).toBe(TokenType.RPAREN);
174
+ expect(tokens[12].type).toBe(TokenType.LBRACE);
175
+ expect(tokens[13].type).toBe(TokenType.RBRACE);
176
+ expect(tokens[14].type).toBe(TokenType.LBRACKET);
177
+ expect(tokens[15].type).toBe(TokenType.RBRACKET);
178
+ });
179
+
180
+ it('throws on unexpected character', () => {
181
+ const lexer = new ReqonLexer('@');
182
+
183
+ expect(() => lexer.tokenize()).toThrow("Unexpected character '@'");
184
+ });
185
+ });
186
+
187
+ describe('comments', () => {
188
+ it('skips single-line comments', () => {
189
+ const lexer = new ReqonLexer('mission // this is a comment\nTestMission');
190
+ const tokens = lexer.tokenize();
191
+
192
+ // Should have: MISSION, NEWLINE, IDENTIFIER, EOF
193
+ expect(tokens.filter((t: Token) => t.type !== TokenType.NEWLINE && t.type !== TokenType.EOF))
194
+ .toHaveLength(2);
195
+ expect(tokens[0].type).toBe(ReqonTokenType.MISSION);
196
+ expect(tokens[2].type).toBe(TokenType.IDENTIFIER);
197
+ expect(tokens[2].value).toBe('TestMission');
198
+ });
199
+
200
+ it('handles comment at end of file', () => {
201
+ const lexer = new ReqonLexer('mission // end comment');
202
+ const tokens = lexer.tokenize();
203
+
204
+ expect(tokens[0].type).toBe(ReqonTokenType.MISSION);
205
+ expect(tokens[tokens.length - 1].type).toBe(TokenType.EOF);
206
+ });
207
+ });
208
+
209
+ describe('line and column tracking', () => {
210
+ it('tracks line numbers', () => {
211
+ const lexer = new ReqonLexer('mission\nTestMission\n{\n}');
212
+ const tokens = lexer.tokenize();
213
+
214
+ expect(tokens[0].line).toBe(1); // mission
215
+ expect(tokens[2].line).toBe(2); // TestMission
216
+ expect(tokens[4].line).toBe(3); // {
217
+ expect(tokens[6].line).toBe(4); // }
218
+ });
219
+
220
+ it('tracks column numbers', () => {
221
+ const lexer = new ReqonLexer('mission TestMission');
222
+ const tokens = lexer.tokenize();
223
+
224
+ expect(tokens[0].column).toBe(1); // mission starts at column 1
225
+ expect(tokens[1].column).toBe(9); // TestMission starts at column 9
226
+ });
227
+
228
+ it('resets column after newline', () => {
229
+ const lexer = new ReqonLexer('abc\nxyz');
230
+ const tokens = lexer.tokenize();
231
+
232
+ expect(tokens[0].column).toBe(1); // abc
233
+ expect(tokens[2].column).toBe(1); // xyz
234
+ });
235
+ });
236
+
237
+ describe('complex tokenization', () => {
238
+ it('tokenizes a complete mission definition', () => {
239
+ const source = `
240
+ mission SyncUsers {
241
+ source API {
242
+ auth: bearer,
243
+ base: "https://api.example.com"
244
+ }
245
+
246
+ store users: memory("users")
247
+
248
+ action FetchUsers {
249
+ get "/users"
250
+ store response -> users {
251
+ key: .id
252
+ }
253
+ }
254
+
255
+ run FetchUsers
256
+ }
257
+ `;
258
+
259
+ const lexer = new ReqonLexer(source);
260
+ const tokens = lexer.tokenize();
261
+
262
+ // Verify it doesn't throw and produces tokens
263
+ expect(tokens.length).toBeGreaterThan(0);
264
+ expect(tokens[tokens.length - 1].type).toBe(TokenType.EOF);
265
+
266
+ // Check key tokens are present
267
+ const tokenTypes = tokens.map((t: Token) => t.type);
268
+ expect(tokenTypes).toContain(ReqonTokenType.MISSION);
269
+ expect(tokenTypes).toContain(ReqonTokenType.SOURCE);
270
+ expect(tokenTypes).toContain(ReqonTokenType.STORE);
271
+ expect(tokenTypes).toContain(ReqonTokenType.ACTION);
272
+ expect(tokenTypes).toContain(ReqonTokenType.GET);
273
+ expect(tokenTypes).toContain(ReqonTokenType.RUN);
274
+ });
275
+
276
+ it('tokenizes pagination options', () => {
277
+ const lexer = new ReqonLexer('paginate offset page cursor until retry');
278
+ const tokens = lexer.tokenize();
279
+
280
+ expect(tokens[0].type).toBe(ReqonTokenType.PAGINATE);
281
+ expect(tokens[1].type).toBe(ReqonTokenType.OFFSET);
282
+ expect(tokens[2].type).toBe(ReqonTokenType.PAGE);
283
+ expect(tokens[3].type).toBe(ReqonTokenType.CURSOR);
284
+ expect(tokens[4].type).toBe(ReqonTokenType.UNTIL);
285
+ expect(tokens[5].type).toBe(ReqonTokenType.RETRY);
286
+ });
287
+
288
+ it('tokenizes store options', () => {
289
+ const lexer = new ReqonLexer('key partial upsert');
290
+ const tokens = lexer.tokenize();
291
+
292
+ expect(tokens[0].type).toBe(ReqonTokenType.KEY);
293
+ expect(tokens[1].type).toBe(ReqonTokenType.PARTIAL);
294
+ expect(tokens[2].type).toBe(ReqonTokenType.UPSERT);
295
+ });
296
+ });
297
+
298
+ describe('whitespace handling', () => {
299
+ it('skips spaces and tabs', () => {
300
+ const lexer = new ReqonLexer(' mission \t action ');
301
+ const tokens = lexer.tokenize();
302
+
303
+ const nonEofTokens = tokens.filter((t: Token) => t.type !== TokenType.EOF);
304
+ expect(nonEofTokens).toHaveLength(2);
305
+ expect(nonEofTokens[0].type).toBe(ReqonTokenType.MISSION);
306
+ expect(nonEofTokens[1].type).toBe(ReqonTokenType.ACTION);
307
+ });
308
+
309
+ it('tracks newlines as tokens', () => {
310
+ const lexer = new ReqonLexer('a\nb\nc');
311
+ const tokens = lexer.tokenize();
312
+
313
+ expect(tokens.filter((t: Token) => t.type === TokenType.NEWLINE)).toHaveLength(2);
314
+ });
315
+ });
316
+ });
@@ -0,0 +1,179 @@
1
+ import { TokenType as VagueTokenType } from 'vague-lang';
2
+
3
+ // Extend Vague's TokenType with Reqon-specific tokens
4
+ export enum ReqonTokenType {
5
+ // Reqon keywords
6
+ MISSION = 'MISSION',
7
+ ACTION = 'ACTION',
8
+ SOURCE = 'SOURCE',
9
+ STORE = 'STORE',
10
+ CALL = 'CALL',
11
+ RUN = 'RUN',
12
+ FOR = 'FOR',
13
+ MAP = 'MAP',
14
+ EACH = 'EACH',
15
+ PAGINATE = 'PAGINATE',
16
+ UNTIL = 'UNTIL',
17
+ RETRY = 'RETRY',
18
+ KEY = 'KEY',
19
+ PARTIAL = 'PARTIAL',
20
+ UPSERT = 'UPSERT',
21
+ SINCE = 'SINCE',
22
+ LAST_SYNC = 'LAST_SYNC',
23
+
24
+ // HTTP methods
25
+ GET = 'GET',
26
+ POST = 'POST',
27
+ PUT = 'PUT',
28
+ PATCH = 'PATCH',
29
+ DELETE = 'DELETE',
30
+
31
+ // Store types
32
+ NOSQL = 'NOSQL',
33
+ SQL = 'SQL',
34
+ MEMORY = 'MEMORY',
35
+
36
+ // Auth types
37
+ OAUTH2 = 'OAUTH2',
38
+ BEARER = 'BEARER',
39
+ BASIC = 'BASIC',
40
+ API_KEY = 'API_KEY',
41
+ NONE = 'NONE',
42
+
43
+ // Pagination types
44
+ OFFSET = 'OFFSET',
45
+ CURSOR = 'CURSOR',
46
+ PAGE = 'PAGE',
47
+
48
+ // Additional operators (RIGHT_ARROW is now in Vague)
49
+ NOT_EQUALS = 'NOT_EQUALS', // !=
50
+ BANG = 'BANG', // !
51
+ // OAS integration
52
+ FROM = 'FROM',
53
+
54
+ // Scheduling
55
+ SCHEDULE = 'SCHEDULE',
56
+ CRON = 'CRON',
57
+ EVERY = 'EVERY',
58
+ AT = 'AT',
59
+ HOURS = 'HOURS',
60
+ MINUTES = 'MINUTES',
61
+ SECONDS = 'SECONDS',
62
+ DAYS = 'DAYS',
63
+ WEEKS = 'WEEKS',
64
+
65
+ // Flow control directives
66
+ CONTINUE = 'CONTINUE',
67
+ SKIP = 'SKIP',
68
+ ABORT = 'ABORT',
69
+ QUEUE = 'QUEUE',
70
+ JUMP = 'JUMP',
71
+
72
+ // Type checking
73
+ IS = 'IS',
74
+
75
+ // Webhook support
76
+ WAIT = 'WAIT',
77
+ TIMEOUT = 'TIMEOUT',
78
+ PATH = 'PATH',
79
+ EXPECTED_EVENTS = 'EXPECTED_EVENTS',
80
+ EVENT_FILTER = 'EVENT_FILTER',
81
+ STORAGE = 'STORAGE',
82
+ }
83
+
84
+ // Combined token type
85
+ export type TokenType = VagueTokenType | ReqonTokenType;
86
+
87
+ // Re-export Vague's TokenType for convenience
88
+ export { TokenType as VagueTokenType } from 'vague-lang';
89
+
90
+ // Reqon-specific keywords
91
+ export const REQON_KEYWORDS: Record<string, ReqonTokenType> = {
92
+ mission: ReqonTokenType.MISSION,
93
+ action: ReqonTokenType.ACTION,
94
+ source: ReqonTokenType.SOURCE,
95
+ store: ReqonTokenType.STORE,
96
+ call: ReqonTokenType.CALL,
97
+ run: ReqonTokenType.RUN,
98
+ for: ReqonTokenType.FOR,
99
+ map: ReqonTokenType.MAP,
100
+ each: ReqonTokenType.EACH,
101
+ paginate: ReqonTokenType.PAGINATE,
102
+ until: ReqonTokenType.UNTIL,
103
+ retry: ReqonTokenType.RETRY,
104
+ key: ReqonTokenType.KEY,
105
+ partial: ReqonTokenType.PARTIAL,
106
+ upsert: ReqonTokenType.UPSERT,
107
+ since: ReqonTokenType.SINCE,
108
+ lastSync: ReqonTokenType.LAST_SYNC,
109
+
110
+ // HTTP methods (both lowercase and uppercase)
111
+ get: ReqonTokenType.GET,
112
+ post: ReqonTokenType.POST,
113
+ put: ReqonTokenType.PUT,
114
+ patch: ReqonTokenType.PATCH,
115
+ delete: ReqonTokenType.DELETE,
116
+ GET: ReqonTokenType.GET,
117
+ POST: ReqonTokenType.POST,
118
+ PUT: ReqonTokenType.PUT,
119
+ PATCH: ReqonTokenType.PATCH,
120
+ DELETE: ReqonTokenType.DELETE,
121
+
122
+ // Store types
123
+ nosql: ReqonTokenType.NOSQL,
124
+ sql: ReqonTokenType.SQL,
125
+ memory: ReqonTokenType.MEMORY,
126
+
127
+ // Auth types
128
+ oauth2: ReqonTokenType.OAUTH2,
129
+ bearer: ReqonTokenType.BEARER,
130
+ basic: ReqonTokenType.BASIC,
131
+ api_key: ReqonTokenType.API_KEY,
132
+ none: ReqonTokenType.NONE,
133
+
134
+ // Pagination types
135
+ offset: ReqonTokenType.OFFSET,
136
+ cursor: ReqonTokenType.CURSOR,
137
+ page: ReqonTokenType.PAGE,
138
+
139
+ // OAS integration
140
+ from: ReqonTokenType.FROM,
141
+
142
+ // Scheduling
143
+ schedule: ReqonTokenType.SCHEDULE,
144
+ cron: ReqonTokenType.CRON,
145
+ every: ReqonTokenType.EVERY,
146
+ at: ReqonTokenType.AT,
147
+ hours: ReqonTokenType.HOURS,
148
+ minutes: ReqonTokenType.MINUTES,
149
+ seconds: ReqonTokenType.SECONDS,
150
+ days: ReqonTokenType.DAYS,
151
+ weeks: ReqonTokenType.WEEKS,
152
+
153
+ // Flow control directives
154
+ continue: ReqonTokenType.CONTINUE,
155
+ skip: ReqonTokenType.SKIP,
156
+ abort: ReqonTokenType.ABORT,
157
+ queue: ReqonTokenType.QUEUE,
158
+ jump: ReqonTokenType.JUMP,
159
+
160
+ // Type checking
161
+ is: ReqonTokenType.IS,
162
+
163
+ // Webhook support
164
+ wait: ReqonTokenType.WAIT,
165
+ timeout: ReqonTokenType.TIMEOUT,
166
+ path: ReqonTokenType.PATH,
167
+ expectedEvents: ReqonTokenType.EXPECTED_EVENTS,
168
+ eventFilter: ReqonTokenType.EVENT_FILTER,
169
+ storage: ReqonTokenType.STORAGE,
170
+ };
171
+
172
+ // ReqonToken is now an alias for Vague's Token
173
+ // Token type can be a string (for plugin-registered keywords)
174
+ export interface ReqonToken {
175
+ type: TokenType | string;
176
+ value: string;
177
+ line: number;
178
+ column: number;
179
+ }