@hyperfixi/core 2.0.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 (381) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +218 -0
  3. package/dist/__test-utils__/context-builders.d.ts +42 -0
  4. package/dist/__test-utils__/error-testing.d.ts +18 -0
  5. package/dist/__test-utils__/index.d.ts +6 -0
  6. package/dist/__test-utils__/mock-types.d.ts +57 -0
  7. package/dist/__test-utils__/parser-context-mock.d.ts +7 -0
  8. package/dist/__test-utils__/parser-helpers.d.ts +38 -0
  9. package/dist/api/dom-processor.d.ts +17 -0
  10. package/dist/api/hyperscript-api.d.ts +68 -0
  11. package/dist/api/lokascript-api.d.ts +9 -0
  12. package/dist/ast-utils/analyzer.d.ts +19 -0
  13. package/dist/ast-utils/documentation.d.ts +8 -0
  14. package/dist/ast-utils/generator.d.ts +9 -0
  15. package/dist/ast-utils/index.d.ts +12 -0
  16. package/dist/ast-utils/index.js +3366 -0
  17. package/dist/ast-utils/index.mjs +3320 -0
  18. package/dist/ast-utils/interchange/from-core.d.ts +8 -0
  19. package/dist/ast-utils/interchange/index.d.ts +6 -0
  20. package/dist/ast-utils/interchange/lsp.d.ts +108 -0
  21. package/dist/ast-utils/interchange/to-core.d.ts +8 -0
  22. package/dist/ast-utils/interchange/types.d.ts +113 -0
  23. package/dist/ast-utils/query.d.ts +25 -0
  24. package/dist/ast-utils/transformer.d.ts +14 -0
  25. package/dist/ast-utils/types.d.ts +162 -0
  26. package/dist/ast-utils/visitor.d.ts +40 -0
  27. package/dist/behaviors/boosted.d.ts +29 -0
  28. package/dist/behaviors/history-swap.d.ts +24 -0
  29. package/dist/behaviors/index.d.ts +4 -0
  30. package/dist/behaviors/index.js +1149 -0
  31. package/dist/behaviors/index.mjs +1139 -0
  32. package/dist/bundle-generator/generator.d.ts +4 -0
  33. package/dist/bundle-generator/index.d.ts +6 -0
  34. package/dist/bundle-generator/index.js +2294 -0
  35. package/dist/bundle-generator/index.mjs +2271 -0
  36. package/dist/bundle-generator/parser-templates.d.ts +6 -0
  37. package/dist/bundle-generator/template-capabilities.d.ts +10 -0
  38. package/dist/bundle-generator/templates.d.ts +11 -0
  39. package/dist/bundle-generator/types.d.ts +34 -0
  40. package/dist/bundles/test-minimal.d.ts +3 -0
  41. package/dist/bundles/test-standard.d.ts +3 -0
  42. package/dist/chunks/bridge-I6ceoWxV.js +2 -0
  43. package/dist/chunks/browser-modular-Dv6PAV3c.js +2 -0
  44. package/dist/chunks/feature-eventsource-DWb514fy.js +2 -0
  45. package/dist/chunks/feature-sockets-3PFuvCVY.js +2 -0
  46. package/dist/chunks/feature-webworker-DTm_eh-E.js +2 -0
  47. package/dist/commands/advanced/async.d.ts +28 -0
  48. package/dist/commands/advanced/js.d.ts +28 -0
  49. package/dist/commands/animation/measure.d.ts +31 -0
  50. package/dist/commands/animation/settle.d.ts +26 -0
  51. package/dist/commands/animation/take.d.ts +28 -0
  52. package/dist/commands/animation/transition.d.ts +31 -0
  53. package/dist/commands/async/fetch.d.ts +44 -0
  54. package/dist/commands/async/wait.d.ts +41 -0
  55. package/dist/commands/behaviors/install.d.ts +41 -0
  56. package/dist/commands/content/append.d.ts +27 -0
  57. package/dist/commands/control-flow/break.d.ts +15 -0
  58. package/dist/commands/control-flow/continue.d.ts +15 -0
  59. package/dist/commands/control-flow/exit.d.ts +15 -0
  60. package/dist/commands/control-flow/halt.d.ts +25 -0
  61. package/dist/commands/control-flow/if.d.ts +45 -0
  62. package/dist/commands/control-flow/repeat.d.ts +35 -0
  63. package/dist/commands/control-flow/return.d.ts +23 -0
  64. package/dist/commands/control-flow/signal-base.d.ts +25 -0
  65. package/dist/commands/control-flow/throw.d.ts +22 -0
  66. package/dist/commands/control-flow/unless.d.ts +3 -0
  67. package/dist/commands/data/decrement.d.ts +3 -0
  68. package/dist/commands/data/default.d.ts +31 -0
  69. package/dist/commands/data/get.d.ts +23 -0
  70. package/dist/commands/data/increment.d.ts +25 -0
  71. package/dist/commands/data/set.d.ts +56 -0
  72. package/dist/commands/decorators/index.d.ts +30 -0
  73. package/dist/commands/dom/__tests__/add-standalone-helpers.d.ts +11 -0
  74. package/dist/commands/dom/add.d.ts +31 -0
  75. package/dist/commands/dom/dom-modification-base.d.ts +48 -0
  76. package/dist/commands/dom/hide.d.ts +12 -0
  77. package/dist/commands/dom/make.d.ts +21 -0
  78. package/dist/commands/dom/process-partials.d.ts +39 -0
  79. package/dist/commands/dom/put.d.ts +31 -0
  80. package/dist/commands/dom/remove.d.ts +33 -0
  81. package/dist/commands/dom/show.d.ts +13 -0
  82. package/dist/commands/dom/swap.d.ts +38 -0
  83. package/dist/commands/dom/toggle.d.ts +55 -0
  84. package/dist/commands/dom/visibility-base.d.ts +20 -0
  85. package/dist/commands/events/send.d.ts +3 -0
  86. package/dist/commands/events/trigger.d.ts +36 -0
  87. package/dist/commands/execution/call.d.ts +24 -0
  88. package/dist/commands/execution/pseudo-command.d.ts +42 -0
  89. package/dist/commands/helpers/attribute-manipulation.d.ts +11 -0
  90. package/dist/commands/helpers/batch-dom-operations.d.ts +12 -0
  91. package/dist/commands/helpers/class-manipulation.d.ts +11 -0
  92. package/dist/commands/helpers/condition-helpers.d.ts +4 -0
  93. package/dist/commands/helpers/dom-mutation.d.ts +15 -0
  94. package/dist/commands/helpers/duration-parsing.d.ts +8 -0
  95. package/dist/commands/helpers/element-property-access.d.ts +7 -0
  96. package/dist/commands/helpers/element-resolution.d.ts +17 -0
  97. package/dist/commands/helpers/error-helpers.d.ts +17 -0
  98. package/dist/commands/helpers/event-helpers.d.ts +13 -0
  99. package/dist/commands/helpers/event-waiting.d.ts +37 -0
  100. package/dist/commands/helpers/index.d.ts +32 -0
  101. package/dist/commands/helpers/input-validator.d.ts +23 -0
  102. package/dist/commands/helpers/loop-executor.d.ts +53 -0
  103. package/dist/commands/helpers/numeric-target-parser.d.ts +14 -0
  104. package/dist/commands/helpers/property-target.d.ts +30 -0
  105. package/dist/commands/helpers/selector-type-detection.d.ts +24 -0
  106. package/dist/commands/helpers/smart-element.d.ts +16 -0
  107. package/dist/commands/helpers/style-manipulation.d.ts +16 -0
  108. package/dist/commands/helpers/temporal-modifiers.d.ts +15 -0
  109. package/dist/commands/helpers/url-argument-parser.d.ts +10 -0
  110. package/dist/commands/helpers/url-validation.d.ts +7 -0
  111. package/dist/commands/helpers/variable-access.d.ts +10 -0
  112. package/dist/commands/helpers/visibility-target-parser.d.ts +11 -0
  113. package/dist/commands/index.d.ts +139 -0
  114. package/dist/commands/index.js +9186 -0
  115. package/dist/commands/index.mjs +9032 -0
  116. package/dist/commands/navigation/go.d.ts +35 -0
  117. package/dist/commands/navigation/push-url.d.ts +35 -0
  118. package/dist/commands/navigation/replace-url.d.ts +3 -0
  119. package/dist/commands/templates/render.d.ts +48 -0
  120. package/dist/commands/utility/beep.d.ts +32 -0
  121. package/dist/commands/utility/copy.d.ts +29 -0
  122. package/dist/commands/utility/log.d.ts +24 -0
  123. package/dist/commands/utility/pick.d.ts +26 -0
  124. package/dist/commands/utility/tell.d.ts +26 -0
  125. package/dist/compatibility/browser-bundle-animation-generated.d.ts +16 -0
  126. package/dist/compatibility/browser-bundle-classic-i18n.d.ts +63 -0
  127. package/dist/compatibility/browser-bundle-classic.d.ts +17 -0
  128. package/dist/compatibility/browser-bundle-forms-generated.d.ts +16 -0
  129. package/dist/compatibility/browser-bundle-hybrid-complete.d.ts +28 -0
  130. package/dist/compatibility/browser-bundle-hybrid-hx.d.ts +43 -0
  131. package/dist/compatibility/browser-bundle-lite-plus.d.ts +25 -0
  132. package/dist/compatibility/browser-bundle-lite.d.ts +23 -0
  133. package/dist/compatibility/browser-bundle-minimal-generated.d.ts +16 -0
  134. package/dist/compatibility/browser-bundle-minimal-v2.d.ts +17 -0
  135. package/dist/compatibility/browser-bundle-minimal.d.ts +8 -0
  136. package/dist/compatibility/browser-bundle-modular.d.ts +18 -0
  137. package/dist/compatibility/browser-bundle-multilingual.d.ts +19 -0
  138. package/dist/compatibility/browser-bundle-semantic-complete.d.ts +24 -0
  139. package/dist/compatibility/browser-bundle-standard-v2.d.ts +17 -0
  140. package/dist/compatibility/browser-bundle-standard.d.ts +8 -0
  141. package/dist/compatibility/browser-bundle-textshelf-minimal.d.ts +16 -0
  142. package/dist/compatibility/browser-bundle-textshelf-profile.d.ts +18 -0
  143. package/dist/compatibility/browser-bundle.d.ts +140 -0
  144. package/dist/compatibility/browser-modular.d.ts +53 -0
  145. package/dist/compatibility/browser-tests/test-utils.d.ts +21 -0
  146. package/dist/compatibility/eval-hyperscript.d.ts +15 -0
  147. package/dist/compatibility/feature-loader.d.ts +8 -0
  148. package/dist/compatibility/hyperscript-adapter.d.ts +38 -0
  149. package/dist/compatibility/hyperscript-tests/test-adapter.d.ts +13 -0
  150. package/dist/core/ast-property-utils.d.ts +2 -0
  151. package/dist/core/base-expression-evaluator.d.ts +70 -0
  152. package/dist/core/binary-expression-evaluator.d.ts +7 -0
  153. package/dist/core/call-expression-evaluator.d.ts +7 -0
  154. package/dist/core/configurable-expression-evaluator.d.ts +5 -0
  155. package/dist/core/context.d.ts +15 -0
  156. package/dist/core/dom.d.ts +15 -0
  157. package/dist/core/evaluator-types.d.ts +5 -0
  158. package/dist/core/events.d.ts +48 -0
  159. package/dist/core/executor.d.ts +34 -0
  160. package/dist/core/expression-evaluator.d.ts +6 -0
  161. package/dist/core/lazy-expression-evaluator.d.ts +22 -0
  162. package/dist/core/parser.d.ts +21 -0
  163. package/dist/core/selector-evaluator.d.ts +15 -0
  164. package/dist/core/template-literal-evaluator.d.ts +5 -0
  165. package/dist/dom/attribute-processor.d.ts +40 -0
  166. package/dist/dom/minimal-attribute-processor.d.ts +20 -0
  167. package/dist/experimental/binary-tree/accessor.d.ts +10 -0
  168. package/dist/experimental/binary-tree/ast-serializer.d.ts +26 -0
  169. package/dist/experimental/binary-tree/benchmark.d.ts +24 -0
  170. package/dist/experimental/binary-tree/buffer-context.d.ts +27 -0
  171. package/dist/experimental/binary-tree/deserializer.d.ts +17 -0
  172. package/dist/experimental/binary-tree/index.d.ts +22 -0
  173. package/dist/experimental/binary-tree/serializer.d.ts +4 -0
  174. package/dist/experimental/binary-tree/types.d.ts +54 -0
  175. package/dist/expressions/base-expression.d.ts +27 -0
  176. package/dist/expressions/bundles/common-expressions.d.ts +9 -0
  177. package/dist/expressions/bundles/core-expressions.d.ts +7 -0
  178. package/dist/expressions/bundles/full-expressions.d.ts +10 -0
  179. package/dist/expressions/bundles/index.d.ts +7 -0
  180. package/dist/expressions/comparison/index.d.ts +80 -0
  181. package/dist/expressions/comparison/utils.d.ts +2 -0
  182. package/dist/expressions/conversion/impl/bridge.d.ts +117 -0
  183. package/dist/expressions/conversion/impl/index.d.ts +59 -0
  184. package/dist/expressions/conversion/index.d.ts +23 -0
  185. package/dist/expressions/expression-tiers.d.ts +13 -0
  186. package/dist/expressions/index.d.ts +11 -0
  187. package/dist/expressions/index.js +6930 -0
  188. package/dist/expressions/index.mjs +6912 -0
  189. package/dist/expressions/logical/impl/index.d.ts +54 -0
  190. package/dist/expressions/logical/impl/pattern-matching.d.ts +58 -0
  191. package/dist/expressions/logical/index.d.ts +59 -0
  192. package/dist/expressions/mathematical/index.d.ts +69 -0
  193. package/dist/expressions/positional/impl/bridge.d.ts +95 -0
  194. package/dist/expressions/positional/impl/index.d.ts +73 -0
  195. package/dist/expressions/positional/index.d.ts +26 -0
  196. package/dist/expressions/properties/impl/index.d.ts +105 -0
  197. package/dist/expressions/properties/index.d.ts +26 -0
  198. package/dist/expressions/property/index.d.ts +55 -0
  199. package/dist/expressions/property-access-utils.d.ts +23 -0
  200. package/dist/expressions/references/impl/bridge.d.ts +54 -0
  201. package/dist/expressions/references/impl/index.d.ts +65 -0
  202. package/dist/expressions/references/index.d.ts +40 -0
  203. package/dist/expressions/shared/comparison-utils.d.ts +10 -0
  204. package/dist/expressions/shared/index.d.ts +9 -0
  205. package/dist/expressions/shared/number-utils.d.ts +7 -0
  206. package/dist/expressions/shared/validation-utils.d.ts +13 -0
  207. package/dist/expressions/special/index.d.ts +104 -0
  208. package/dist/expressions/type-helpers.d.ts +11 -0
  209. package/dist/expressions/type-registry.d.ts +57 -0
  210. package/dist/expressions/validation-helpers.d.ts +15 -0
  211. package/dist/extensions/index.d.ts +3 -0
  212. package/dist/extensions/tailwind.d.ts +22 -0
  213. package/dist/features/behaviors.d.ts +153 -0
  214. package/dist/features/def.d.ts +135 -0
  215. package/dist/features/eventsource.d.ts +140 -0
  216. package/dist/features/init.d.ts +135 -0
  217. package/dist/features/on.d.ts +131 -0
  218. package/dist/features/predefined-behaviors/dropdown-behavior.d.ts +20 -0
  219. package/dist/features/predefined-behaviors/index.d.ts +12 -0
  220. package/dist/features/predefined-behaviors/modal-behavior.d.ts +18 -0
  221. package/dist/features/predefined-behaviors/toggle-group-behavior.d.ts +23 -0
  222. package/dist/features/predefined-behaviors/types.d.ts +14 -0
  223. package/dist/features/sockets.d.ts +162 -0
  224. package/dist/features/webworker.d.ts +135 -0
  225. package/dist/htmx/htmx-attribute-processor.d.ts +84 -0
  226. package/dist/htmx/htmx-translator.d.ts +19 -0
  227. package/dist/htmx/index.d.ts +3 -0
  228. package/dist/hyperfixi-classic-i18n.js +2 -0
  229. package/dist/hyperfixi-hx.js +1 -0
  230. package/dist/hyperfixi-hybrid-complete.js +1 -0
  231. package/dist/hyperfixi-lite-plus.js +1 -0
  232. package/dist/hyperfixi-lite.js +1 -0
  233. package/dist/hyperfixi-minimal.js +1 -0
  234. package/dist/hyperfixi-multilingual.js +2 -0
  235. package/dist/hyperfixi-standard.js +2 -0
  236. package/dist/hyperfixi.js +2 -0
  237. package/dist/hyperfixi.mjs +2 -0
  238. package/dist/index.d.ts +25 -0
  239. package/dist/index.js +65387 -0
  240. package/dist/index.min.js +2 -0
  241. package/dist/index.mjs +65343 -0
  242. package/dist/lib/index.d.ts +4 -0
  243. package/dist/lib/morph-adapter.d.ts +22 -0
  244. package/dist/lib/swap-executor.d.ts +22 -0
  245. package/dist/lib/view-transitions.d.ts +33 -0
  246. package/dist/lokascript-browser-classic-i18n.js +2 -0
  247. package/dist/lokascript-browser-minimal.js +1 -0
  248. package/dist/lokascript-browser-standard.js +2 -0
  249. package/dist/lokascript-browser.js +2 -0
  250. package/dist/lokascript-hybrid-complete.js +1 -0
  251. package/dist/lokascript-hybrid-hx.js +1 -0
  252. package/dist/lokascript-lite-plus.js +1 -0
  253. package/dist/lokascript-lite.js +1 -0
  254. package/dist/lokascript-multilingual.js +2 -0
  255. package/dist/lsp-metadata.d.ts +25 -0
  256. package/dist/lsp-metadata.js +680 -0
  257. package/dist/lsp-metadata.mjs +670 -0
  258. package/dist/metadata.d.ts +213 -0
  259. package/dist/metadata.js +378 -0
  260. package/dist/metadata.mjs +368 -0
  261. package/dist/mod.d.ts +63 -0
  262. package/dist/multilingual/bridge.d.ts +36 -0
  263. package/dist/multilingual/index.d.ts +32 -0
  264. package/dist/multilingual/index.js +285 -0
  265. package/dist/multilingual/index.mjs +278 -0
  266. package/dist/parser/__types__/test-helpers.d.ts +25 -0
  267. package/dist/parser/command-node-builder.d.ts +45 -0
  268. package/dist/parser/command-parsers/animation-commands.d.ts +5 -0
  269. package/dist/parser/command-parsers/async-commands.d.ts +5 -0
  270. package/dist/parser/command-parsers/control-flow-commands.d.ts +7 -0
  271. package/dist/parser/command-parsers/dom-commands.d.ts +8 -0
  272. package/dist/parser/command-parsers/event-commands.d.ts +4 -0
  273. package/dist/parser/command-parsers/utility-commands.d.ts +9 -0
  274. package/dist/parser/command-parsers/variable-commands.d.ts +12 -0
  275. package/dist/parser/error-handler.d.ts +34 -0
  276. package/dist/parser/expression-parser.d.ts +6 -0
  277. package/dist/parser/full-parser.d.ts +4 -0
  278. package/dist/parser/full-parser.js +6532 -0
  279. package/dist/parser/full-parser.mjs +6529 -0
  280. package/dist/parser/helpers/ast-helpers.d.ts +22 -0
  281. package/dist/parser/helpers/parsing-helpers.d.ts +19 -0
  282. package/dist/parser/helpers/token-helpers.d.ts +28 -0
  283. package/dist/parser/hybrid/aliases.d.ts +7 -0
  284. package/dist/parser/hybrid/aliases.js +44 -0
  285. package/dist/parser/hybrid/aliases.mjs +37 -0
  286. package/dist/parser/hybrid/ast-types.d.ts +97 -0
  287. package/dist/parser/hybrid/ast-types.js +3 -0
  288. package/dist/parser/hybrid/ast-types.mjs +2 -0
  289. package/dist/parser/hybrid/index.d.ts +6 -0
  290. package/dist/parser/hybrid/index.js +1015 -0
  291. package/dist/parser/hybrid/index.mjs +1005 -0
  292. package/dist/parser/hybrid/parser-core.d.ts +57 -0
  293. package/dist/parser/hybrid/parser-core.js +1001 -0
  294. package/dist/parser/hybrid/parser-core.mjs +999 -0
  295. package/dist/parser/hybrid/tokenizer.d.ts +9 -0
  296. package/dist/parser/hybrid/tokenizer.js +242 -0
  297. package/dist/parser/hybrid/tokenizer.mjs +239 -0
  298. package/dist/parser/hybrid-parser.d.ts +10 -0
  299. package/dist/parser/hybrid-parser.js +1078 -0
  300. package/dist/parser/hybrid-parser.mjs +1071 -0
  301. package/dist/parser/parser-constants.d.ts +102 -0
  302. package/dist/parser/parser-interface.d.ts +11 -0
  303. package/dist/parser/parser-types.d.ts +175 -0
  304. package/dist/parser/parser.d.ts +146 -0
  305. package/dist/parser/regex-parser.d.ts +4 -0
  306. package/dist/parser/regex-parser.js +412 -0
  307. package/dist/parser/regex-parser.mjs +409 -0
  308. package/dist/parser/runtime.d.ts +3 -0
  309. package/dist/parser/semantic-integration.d.ts +61 -0
  310. package/dist/parser/token-consumer.d.ts +35 -0
  311. package/dist/parser/token-predicates.d.ts +77 -0
  312. package/dist/parser/tokenizer.d.ts +57 -0
  313. package/dist/parser/types.d.ts +118 -0
  314. package/dist/performance/expression-cache.d.ts +78 -0
  315. package/dist/performance/integration.d.ts +40 -0
  316. package/dist/performance/production-monitor.d.ts +67 -0
  317. package/dist/reference/index.d.ts +41 -0
  318. package/dist/reference/index.js +586 -0
  319. package/dist/reference/index.mjs +577 -0
  320. package/dist/registry/browser-types.d.ts +20 -0
  321. package/dist/registry/browser-types.js +81 -0
  322. package/dist/registry/browser-types.mjs +76 -0
  323. package/dist/registry/context-provider-registry.d.ts +38 -0
  324. package/dist/registry/environment.d.ts +19 -0
  325. package/dist/registry/environment.js +36 -0
  326. package/dist/registry/environment.mjs +30 -0
  327. package/dist/registry/event-source-registry.d.ts +54 -0
  328. package/dist/registry/examples/server-commands.d.ts +6 -0
  329. package/dist/registry/examples/server-event-source.d.ts +32 -0
  330. package/dist/registry/index.d.ts +54 -0
  331. package/dist/registry/index.js +7636 -0
  332. package/dist/registry/index.mjs +7612 -0
  333. package/dist/registry/multilingual/examples.d.ts +16 -0
  334. package/dist/registry/multilingual/index.d.ts +68 -0
  335. package/dist/registry/runtime-integration.d.ts +30 -0
  336. package/dist/registry/universal-types.d.ts +34 -0
  337. package/dist/registry/universal-types.js +91 -0
  338. package/dist/registry/universal-types.mjs +86 -0
  339. package/dist/runtime/cleanup-registry.d.ts +47 -0
  340. package/dist/runtime/command-adapter.d.ts +63 -0
  341. package/dist/runtime/environment.d.ts +75 -0
  342. package/dist/runtime/runtime-base.d.ts +78 -0
  343. package/dist/runtime/runtime-experimental.d.ts +18 -0
  344. package/dist/runtime/runtime-factory.d.ts +30 -0
  345. package/dist/runtime/runtime.d.ts +19 -0
  346. package/dist/runtime/temporal-modifiers.d.ts +37 -0
  347. package/dist/scripts/code-generator.d.ts +64 -0
  348. package/dist/scripts/generate-missing-commands.d.ts +4 -0
  349. package/dist/test-setup.d.ts +45 -0
  350. package/dist/test-utilities.d.ts +52 -0
  351. package/dist/tokenizer.d.ts +49 -0
  352. package/dist/types/base-types.d.ts +336 -0
  353. package/dist/types/code-fix.d.ts +39 -0
  354. package/dist/types/command-metadata.d.ts +57 -0
  355. package/dist/types/command-types.d.ts +272 -0
  356. package/dist/types/context-types.d.ts +106 -0
  357. package/dist/types/core-context.d.ts +21 -0
  358. package/dist/types/core.d.ts +203 -0
  359. package/dist/types/error-codes.d.ts +207 -0
  360. package/dist/types/expression-types.d.ts +155 -0
  361. package/dist/types/feature-types.d.ts +81 -0
  362. package/dist/types/hooks.d.ts +45 -0
  363. package/dist/types/index.d.ts +32 -0
  364. package/dist/types/result.d.ts +72 -0
  365. package/dist/types/template-types.d.ts +162 -0
  366. package/dist/types/type-guards.d.ts +24 -0
  367. package/dist/types/unified-types.d.ts +99 -0
  368. package/dist/utils/debug-events.d.ts +41 -0
  369. package/dist/utils/debug.d.ts +35 -0
  370. package/dist/utils/dom-utils.d.ts +16 -0
  371. package/dist/utils/element-check.d.ts +7 -0
  372. package/dist/utils/keyboard-shortcuts.d.ts +18 -0
  373. package/dist/utils/performance.d.ts +40 -0
  374. package/dist/validation/command-pattern-validator.d.ts +53 -0
  375. package/dist/validation/common-validators.d.ts +24 -0
  376. package/dist/validation/lightweight-validators.d.ts +113 -0
  377. package/dist/validation/partial-validation-types.d.ts +50 -0
  378. package/dist/validation/partial-validator.d.ts +6 -0
  379. package/dist/validation/partial-warning-formatter.d.ts +6 -0
  380. package/dist/validation/validate-cli.d.ts +41 -0
  381. package/package.json +292 -0
@@ -0,0 +1,2271 @@
1
+ function stripTypes(code, format) {
2
+ if (format === 'ts')
3
+ return code;
4
+ return (code
5
+ .replace(/\s+as\s+\w+(?:\[\])?/g, '')
6
+ .replace(/\((\w+):\s*\w+\)/g, '($1)')
7
+ .replace(/\((\w+):\s*any\)/g, '($1)')
8
+ .replace(/Promise<void>\[\]/g, 'Promise[]')
9
+ .replace(/Promise<void>/g, 'Promise')
10
+ .replace(/:\s*TransitionEvent/g, ''));
11
+ }
12
+ const COMMAND_IMPLEMENTATIONS_TS = {
13
+ toggle: `
14
+ case 'toggle': {
15
+ const className = getClassName(cmd.args[0]) || String(await evaluate(cmd.args[0], ctx));
16
+ const targets = await getTarget();
17
+ for (const el of targets) el.classList.toggle(className);
18
+ ctx.it = targets.length === 1 ? targets[0] : targets;
19
+ return ctx.it;
20
+ }`,
21
+ add: `
22
+ case 'add': {
23
+ const className = getClassName(cmd.args[0]) || String(await evaluate(cmd.args[0], ctx));
24
+ const targets = await getTarget();
25
+ for (const el of targets) el.classList.add(className);
26
+ ctx.it = targets.length === 1 ? targets[0] : targets;
27
+ return ctx.it;
28
+ }`,
29
+ remove: `
30
+ case 'remove': {
31
+ const targets = await getTarget();
32
+ for (const el of targets) el.remove();
33
+ return null;
34
+ }`,
35
+ removeClass: `
36
+ case 'removeClass': {
37
+ const className = getClassName(cmd.args[0]) || String(await evaluate(cmd.args[0], ctx));
38
+ const targets = await getTarget();
39
+ for (const el of targets) el.classList.remove(className);
40
+ return targets;
41
+ }`,
42
+ show: `
43
+ case 'show': {
44
+ const targets = await getTarget();
45
+ for (const el of targets) {
46
+ (el as HTMLElement).style.display = '';
47
+ el.classList.remove('hidden');
48
+ }
49
+ return targets;
50
+ }`,
51
+ hide: `
52
+ case 'hide': {
53
+ const targets = await getTarget();
54
+ for (const el of targets) (el as HTMLElement).style.display = 'none';
55
+ return targets;
56
+ }`,
57
+ set: `
58
+ case 'set': {
59
+ const target = cmd.args[0];
60
+ const value = await evaluate(cmd.args[1], ctx);
61
+
62
+ if (target.type === 'variable') {
63
+ const varName = target.name.slice(1);
64
+ const map = target.scope === 'local' ? ctx.locals : globalVars;
65
+ map.set(varName, value);
66
+ ctx.it = value;
67
+ return value;
68
+ }
69
+
70
+ if (target.type === 'possessive' || target.type === 'member') {
71
+ const obj = await evaluate(target.object, ctx);
72
+ if (obj) {
73
+ if (obj instanceof Element && isStyleProp(target.property)) {
74
+ setStyleProp(obj, target.property, value);
75
+ } else {
76
+ (obj as any)[target.property] = value;
77
+ }
78
+ ctx.it = value;
79
+ return value;
80
+ }
81
+ }
82
+
83
+ ctx.it = value;
84
+ return value;
85
+ }`,
86
+ get: `
87
+ case 'get': {
88
+ const value = await evaluate(cmd.args[0], ctx);
89
+ ctx.it = value;
90
+ return value;
91
+ }`,
92
+ wait: `
93
+ case 'wait': {
94
+ const duration = await evaluate(cmd.args[0], ctx);
95
+ const ms = typeof duration === 'number' ? duration : parseInt(String(duration));
96
+ await new Promise(resolve => setTimeout(resolve, ms));
97
+ return ms;
98
+ }`,
99
+ transition: `
100
+ case 'transition': {
101
+ const property = String(await evaluate(cmd.args[0], ctx)).replace(/^\\*/, '');
102
+ const toValue = await evaluate(cmd.args[1], ctx);
103
+ const durationVal = await evaluate(cmd.args[2], ctx);
104
+ const duration = typeof durationVal === 'number' ? durationVal :
105
+ String(durationVal).endsWith('ms') ? parseInt(String(durationVal)) :
106
+ String(durationVal).endsWith('s') ? parseFloat(String(durationVal)) * 1000 :
107
+ parseInt(String(durationVal)) || 300;
108
+
109
+ const targets = await getTarget();
110
+ const promises: Promise<void>[] = [];
111
+
112
+ for (const el of targets) {
113
+ const htmlEl = el as HTMLElement;
114
+ const kebabProp = property.replace(/([A-Z])/g, '-$1').toLowerCase();
115
+
116
+ const oldTransition = htmlEl.style.transition;
117
+ htmlEl.style.transition = \`\${kebabProp} \${duration}ms ease\`;
118
+ htmlEl.style.setProperty(kebabProp, String(toValue));
119
+
120
+ promises.push(new Promise<void>(resolve => {
121
+ const cleanup = () => {
122
+ htmlEl.style.transition = oldTransition;
123
+ resolve();
124
+ };
125
+
126
+ const onEnd = (e: TransitionEvent) => {
127
+ if (e.propertyName === kebabProp) {
128
+ htmlEl.removeEventListener('transitionend', onEnd);
129
+ cleanup();
130
+ }
131
+ };
132
+
133
+ htmlEl.addEventListener('transitionend', onEnd);
134
+ setTimeout(cleanup, duration + 50);
135
+ }));
136
+ }
137
+
138
+ await Promise.all(promises);
139
+ ctx.it = targets.length === 1 ? targets[0] : targets;
140
+ return ctx.it;
141
+ }`,
142
+ go: `
143
+ case 'go': {
144
+ const dest = await evaluate(cmd.args[0], ctx);
145
+ const d = String(dest).toLowerCase();
146
+ if (d === 'back') history.back();
147
+ else if (d === 'forward') history.forward();
148
+ else if (d === 'bottom') ctx.me.scrollIntoView({ block: 'end', behavior: 'smooth' });
149
+ else if (d === 'top') ctx.me.scrollIntoView({ block: 'start', behavior: 'smooth' });
150
+ else window.location.href = String(dest);
151
+ return null;
152
+ }`,
153
+ call: `
154
+ case 'call': {
155
+ const result = await evaluate(cmd.args[0], ctx);
156
+ ctx.it = result;
157
+ return result;
158
+ }`,
159
+ log: `
160
+ case 'log': {
161
+ const values = await Promise.all(cmd.args.map((a: any) => evaluate(a, ctx)));
162
+ console.log(...values);
163
+ return values[0];
164
+ }`,
165
+ send: `
166
+ case 'send': {
167
+ const eventName = await evaluate(cmd.args[0], ctx);
168
+ const targets = await getTarget();
169
+ const event = new CustomEvent(String(eventName), { bubbles: true, detail: ctx.it });
170
+ for (const el of targets) el.dispatchEvent(event);
171
+ ctx.it = event;
172
+ return event;
173
+ }`,
174
+ trigger: `
175
+ case 'trigger': {
176
+ const eventName = await evaluate(cmd.args[0], ctx);
177
+ const targets = await getTarget();
178
+ const event = new CustomEvent(String(eventName), { bubbles: true, detail: ctx.it });
179
+ for (const el of targets) el.dispatchEvent(event);
180
+ ctx.it = event;
181
+ return event;
182
+ }`,
183
+ put: `
184
+ case 'put': {
185
+ const content = await evaluate(cmd.args[0], ctx);
186
+ const modifier = cmd.modifier || 'into';
187
+
188
+ if (cmd.target?.type === 'possessive' && isStyleProp(cmd.target.property)) {
189
+ const obj = await evaluate(cmd.target.object, ctx);
190
+ const elements = toElementArray(obj);
191
+ for (const el of elements) {
192
+ setStyleProp(el, cmd.target.property, content);
193
+ }
194
+ ctx.it = content;
195
+ return content;
196
+ }
197
+
198
+ const targets = await getTarget();
199
+ for (const el of targets) {
200
+ const html = String(content);
201
+ if (modifier === 'into') el.innerHTML = html;
202
+ else if (modifier === 'before') el.insertAdjacentHTML('beforebegin', html);
203
+ else if (modifier === 'after') el.insertAdjacentHTML('afterend', html);
204
+ else if (modifier === 'at start of') el.insertAdjacentHTML('afterbegin', html);
205
+ else if (modifier === 'at end of') el.insertAdjacentHTML('beforeend', html);
206
+ }
207
+ ctx.it = content;
208
+ return content;
209
+ }`,
210
+ append: `
211
+ case 'append': {
212
+ const content = await evaluate(cmd.args[0], ctx);
213
+ const targets = await getTarget();
214
+ for (const el of targets) el.insertAdjacentHTML('beforeend', String(content));
215
+ ctx.it = content;
216
+ return content;
217
+ }`,
218
+ morph: `
219
+ case 'morph': {
220
+ const targets = await getTarget();
221
+ const content = await evaluate(cmd.args[0], ctx);
222
+ const contentStr = String(content);
223
+ const isOuter = cmd.modifier === 'over';
224
+
225
+ for (const target of targets) {
226
+ try {
227
+ if (isOuter) {
228
+ morphlexMorph(target, contentStr);
229
+ } else {
230
+ morphlexMorphInner(target, contentStr);
231
+ }
232
+ } catch (error) {
233
+ // Fallback to innerHTML/outerHTML if morph fails
234
+ console.warn('[LokaScript] Morph failed, falling back:', error);
235
+ if (isOuter) {
236
+ target.outerHTML = contentStr;
237
+ } else {
238
+ target.innerHTML = contentStr;
239
+ }
240
+ }
241
+ }
242
+ ctx.it = targets.length === 1 ? targets[0] : targets;
243
+ return ctx.it;
244
+ }`,
245
+ take: `
246
+ case 'take': {
247
+ const className = getClassName(await evaluate(cmd.args[0], ctx));
248
+ const from = cmd.target ? await getTarget() : [ctx.me.parentElement!];
249
+ for (const container of from) {
250
+ const siblings = container.querySelectorAll('.' + className);
251
+ siblings.forEach(el => el.classList.remove(className));
252
+ }
253
+ ctx.me.classList.add(className);
254
+ return ctx.me;
255
+ }`,
256
+ increment: `
257
+ case 'increment': {
258
+ const target = cmd.args[0];
259
+ const amount = cmd.args[1] ? await evaluate(cmd.args[1], ctx) : 1;
260
+
261
+ if (target.type === 'variable') {
262
+ const varName = target.name.slice(1);
263
+ const map = target.scope === 'local' ? ctx.locals : globalVars;
264
+ const current = map.get(varName) || 0;
265
+ const newVal = current + amount;
266
+ map.set(varName, newVal);
267
+ ctx.it = newVal;
268
+ return newVal;
269
+ }
270
+
271
+ const elements = toElementArray(await evaluate(target, ctx));
272
+ for (const el of elements) {
273
+ const current = parseFloat(el.textContent || '0') || 0;
274
+ const newVal = current + amount;
275
+ el.textContent = String(newVal);
276
+ ctx.it = newVal;
277
+ }
278
+ return ctx.it;
279
+ }`,
280
+ decrement: `
281
+ case 'decrement': {
282
+ const target = cmd.args[0];
283
+ const amount = cmd.args[1] ? await evaluate(cmd.args[1], ctx) : 1;
284
+
285
+ if (target.type === 'variable') {
286
+ const varName = target.name.slice(1);
287
+ const map = target.scope === 'local' ? ctx.locals : globalVars;
288
+ const current = map.get(varName) || 0;
289
+ const newVal = current - amount;
290
+ map.set(varName, newVal);
291
+ ctx.it = newVal;
292
+ return newVal;
293
+ }
294
+
295
+ const elements = toElementArray(await evaluate(target, ctx));
296
+ for (const el of elements) {
297
+ const current = parseFloat(el.textContent || '0') || 0;
298
+ const newVal = current - amount;
299
+ el.textContent = String(newVal);
300
+ ctx.it = newVal;
301
+ }
302
+ return ctx.it;
303
+ }`,
304
+ focus: `
305
+ case 'focus': {
306
+ const targets = await getTarget();
307
+ for (const el of targets) (el as HTMLElement).focus();
308
+ return targets;
309
+ }`,
310
+ blur: `
311
+ case 'blur': {
312
+ const targets = await getTarget();
313
+ for (const el of targets) (el as HTMLElement).blur();
314
+ return targets;
315
+ }`,
316
+ return: `
317
+ case 'return': {
318
+ const value = cmd.args[0] ? await evaluate(cmd.args[0], ctx) : ctx.it;
319
+ throw { type: 'return', value };
320
+ }`,
321
+ break: `
322
+ case 'break': {
323
+ throw { type: 'break' };
324
+ }`,
325
+ continue: `
326
+ case 'continue': {
327
+ throw { type: 'continue' };
328
+ }`,
329
+ halt: `
330
+ case 'halt': {
331
+ // Check for "halt the event" pattern
332
+ const firstArg = cmd.args[0];
333
+ let targetEvent = ctx.event;
334
+ if (firstArg?.type === 'identifier' && firstArg.name === 'the' && cmd.args[1]?.name === 'event') {
335
+ targetEvent = ctx.event;
336
+ } else if (firstArg) {
337
+ const evaluated = await evaluate(firstArg, ctx);
338
+ if (evaluated?.preventDefault) targetEvent = evaluated;
339
+ }
340
+
341
+ if (targetEvent && typeof targetEvent.preventDefault === 'function') {
342
+ targetEvent.preventDefault();
343
+ targetEvent.stopPropagation();
344
+ return { halted: true, eventHalted: true };
345
+ }
346
+
347
+ // Regular halt - stop execution
348
+ const haltError = new Error('HALT_EXECUTION');
349
+ (haltError as any).isHalt = true;
350
+ throw haltError;
351
+ }`,
352
+ exit: `
353
+ case 'exit': {
354
+ const exitError = new Error('EXIT_COMMAND');
355
+ (exitError as any).isExit = true;
356
+ throw exitError;
357
+ }`,
358
+ throw: `
359
+ case 'throw': {
360
+ const message = cmd.args[0] ? await evaluate(cmd.args[0], ctx) : 'Error';
361
+ const errorToThrow = message instanceof Error ? message : new Error(String(message));
362
+ throw errorToThrow;
363
+ }`,
364
+ beep: `
365
+ case 'beep': {
366
+ const values = await Promise.all(cmd.args.map((a: any) => evaluate(a, ctx)));
367
+ const displayValues = values.length > 0 ? values : [ctx.it];
368
+
369
+ for (const val of displayValues) {
370
+ const typeInfo = val === null ? 'null' :
371
+ val === undefined ? 'undefined' :
372
+ Array.isArray(val) ? \`Array[\${val.length}]\` :
373
+ val instanceof Element ? \`Element<\${val.tagName.toLowerCase()}>\` :
374
+ typeof val;
375
+ console.log('[beep]', typeInfo + ':', val);
376
+ }
377
+ return displayValues[0];
378
+ }`,
379
+ js: `
380
+ case 'js': {
381
+ const codeArg = cmd.args[0];
382
+ let jsCode = '';
383
+
384
+ if (codeArg.type === 'string') {
385
+ jsCode = codeArg.value;
386
+ } else if (codeArg.type === 'template') {
387
+ jsCode = await evaluate(codeArg, ctx);
388
+ } else {
389
+ jsCode = String(await evaluate(codeArg, ctx));
390
+ }
391
+
392
+ // Build context object for the Function
393
+ const jsContext = {
394
+ me: ctx.me,
395
+ it: ctx.it,
396
+ event: ctx.event,
397
+ target: ctx.target || ctx.me,
398
+ locals: Object.fromEntries(ctx.locals),
399
+ globals: Object.fromEntries(globalVars),
400
+ document: typeof document !== 'undefined' ? document : undefined,
401
+ window: typeof window !== 'undefined' ? window : undefined,
402
+ };
403
+
404
+ try {
405
+ const fn = new Function('ctx', \`with(ctx) { return (async () => { \${jsCode} })(); }\`);
406
+ const result = await fn(jsContext);
407
+ ctx.it = result;
408
+ return result;
409
+ } catch (error) {
410
+ console.error('[js] Execution error:', error);
411
+ throw error;
412
+ }
413
+ }`,
414
+ copy: `
415
+ case 'copy': {
416
+ const source = await evaluate(cmd.args[0], ctx);
417
+ let textToCopy = '';
418
+
419
+ if (typeof source === 'string') {
420
+ textToCopy = source;
421
+ } else if (source instanceof Element) {
422
+ textToCopy = source.textContent || '';
423
+ } else {
424
+ textToCopy = String(source);
425
+ }
426
+
427
+ try {
428
+ if (navigator.clipboard) {
429
+ await navigator.clipboard.writeText(textToCopy);
430
+ } else {
431
+ // Fallback for older browsers
432
+ const textarea = document.createElement('textarea');
433
+ textarea.value = textToCopy;
434
+ textarea.style.cssText = 'position:fixed;top:0;left:-9999px';
435
+ document.body.appendChild(textarea);
436
+ textarea.select();
437
+ document.execCommand('copy');
438
+ document.body.removeChild(textarea);
439
+ }
440
+
441
+ if (ctx.me instanceof Element) {
442
+ ctx.me.dispatchEvent(new CustomEvent('copy:success', {
443
+ bubbles: true,
444
+ detail: { text: textToCopy }
445
+ }));
446
+ }
447
+ ctx.it = textToCopy;
448
+ return textToCopy;
449
+ } catch (error) {
450
+ if (ctx.me instanceof Element) {
451
+ ctx.me.dispatchEvent(new CustomEvent('copy:error', {
452
+ bubbles: true,
453
+ detail: { error }
454
+ }));
455
+ }
456
+ throw error;
457
+ }
458
+ }`,
459
+ push: `
460
+ case 'push':
461
+ case 'push-url': {
462
+ // Handle "push url '/path'" pattern
463
+ let urlArg = cmd.args[0];
464
+ if (urlArg?.type === 'identifier' && urlArg.name === 'url') {
465
+ urlArg = cmd.args[1];
466
+ }
467
+
468
+ const url = String(await evaluate(urlArg, ctx));
469
+ let title = '';
470
+
471
+ // Check for "with title" modifier
472
+ if (cmd.modifiers?.title) {
473
+ title = String(await evaluate(cmd.modifiers.title, ctx));
474
+ }
475
+
476
+ window.history.pushState(null, '', url);
477
+ if (title) document.title = title;
478
+
479
+ window.dispatchEvent(new CustomEvent('lokascript:pushurl', {
480
+ detail: { url, title }
481
+ }));
482
+
483
+ return { url, title, mode: 'push' };
484
+ }`,
485
+ replace: `
486
+ case 'replace':
487
+ case 'replace-url': {
488
+ // Handle "replace url '/path'" pattern
489
+ let urlArg = cmd.args[0];
490
+ if (urlArg?.type === 'identifier' && urlArg.name === 'url') {
491
+ urlArg = cmd.args[1];
492
+ }
493
+
494
+ const url = String(await evaluate(urlArg, ctx));
495
+ let title = '';
496
+
497
+ // Check for "with title" modifier
498
+ if (cmd.modifiers?.title) {
499
+ title = String(await evaluate(cmd.modifiers.title, ctx));
500
+ }
501
+
502
+ window.history.replaceState(null, '', url);
503
+ if (title) document.title = title;
504
+
505
+ window.dispatchEvent(new CustomEvent('lokascript:replaceurl', {
506
+ detail: { url, title }
507
+ }));
508
+
509
+ return { url, title, mode: 'replace' };
510
+ }`,
511
+ };
512
+ const BLOCK_IMPLEMENTATIONS_TS = {
513
+ if: `
514
+ case 'if': {
515
+ const condition = await evaluate(block.condition!, ctx);
516
+ if (condition) {
517
+ return executeSequenceWithBlocks(block.body, ctx);
518
+ } else if (block.elseBody) {
519
+ return executeSequenceWithBlocks(block.elseBody, ctx);
520
+ }
521
+ return null;
522
+ }`,
523
+ repeat: `
524
+ case 'repeat': {
525
+ const count = await evaluate(block.condition!, ctx);
526
+ const n = typeof count === 'number' ? count : parseInt(String(count));
527
+ for (let i = 0; i < n && i < MAX_LOOP_ITERATIONS; i++) {
528
+ ctx.locals.set('__loop_index__', i);
529
+ ctx.locals.set('__loop_count__', i + 1);
530
+ try {
531
+ await executeSequenceWithBlocks(block.body, ctx);
532
+ } catch (e: any) {
533
+ if (e?.type === 'break') break;
534
+ if (e?.type === 'continue') continue;
535
+ throw e;
536
+ }
537
+ }
538
+ return null;
539
+ }`,
540
+ for: `
541
+ case 'for': {
542
+ const { variable, iterable } = block.condition as any;
543
+ const items = await evaluate(iterable, ctx);
544
+ const arr = Array.isArray(items) ? items : items instanceof NodeList ? Array.from(items) : [items];
545
+ const varName = variable.startsWith(':') ? variable.slice(1) : variable;
546
+ for (let i = 0; i < arr.length && i < MAX_LOOP_ITERATIONS; i++) {
547
+ ctx.locals.set(varName, arr[i]);
548
+ ctx.locals.set('__loop_index__', i);
549
+ ctx.locals.set('__loop_count__', i + 1);
550
+ try {
551
+ await executeSequenceWithBlocks(block.body, ctx);
552
+ } catch (e: any) {
553
+ if (e?.type === 'break') break;
554
+ if (e?.type === 'continue') continue;
555
+ throw e;
556
+ }
557
+ }
558
+ return null;
559
+ }`,
560
+ while: `
561
+ case 'while': {
562
+ let iterations = 0;
563
+ while (await evaluate(block.condition!, ctx) && iterations < MAX_LOOP_ITERATIONS) {
564
+ ctx.locals.set('__loop_index__', iterations);
565
+ try {
566
+ await executeSequenceWithBlocks(block.body, ctx);
567
+ } catch (e: any) {
568
+ if (e?.type === 'break') break;
569
+ if (e?.type === 'continue') { iterations++; continue; }
570
+ throw e;
571
+ }
572
+ iterations++;
573
+ }
574
+ return null;
575
+ }`,
576
+ fetch: `
577
+ case 'fetch': {
578
+ const { url, responseType } = block.condition as any;
579
+ try {
580
+ const urlVal = await evaluate(url, ctx);
581
+ const response = await fetch(String(urlVal));
582
+ if (!response.ok) throw new Error(\`HTTP \${response.status}\`);
583
+
584
+ const resType = await evaluate(responseType, ctx);
585
+ let data: any;
586
+ if (resType === 'json') data = await response.json();
587
+ else if (resType === 'html') {
588
+ const text = await response.text();
589
+ const doc = new DOMParser().parseFromString(text, 'text/html');
590
+ data = doc.body.innerHTML;
591
+ } else data = await response.text();
592
+
593
+ ctx.it = data;
594
+ ctx.locals.set('it', data);
595
+ ctx.locals.set('result', data);
596
+ ctx.locals.set('response', response);
597
+
598
+ await executeSequenceWithBlocks(block.body, ctx);
599
+ } catch (error: any) {
600
+ if (error?.type === 'return') throw error;
601
+ ctx.locals.set('error', error);
602
+ console.error('Fetch error:', error);
603
+ }
604
+ return null;
605
+ }`,
606
+ };
607
+ const STYLE_COMMANDS = ['set', 'put', 'increment', 'decrement'];
608
+ const ELEMENT_ARRAY_COMMANDS = ['put', 'increment', 'decrement'];
609
+ const MORPH_COMMANDS = ['morph'];
610
+ function getCommandImplementations(format = 'ts') {
611
+ const result = {};
612
+ for (const [name, code] of Object.entries(COMMAND_IMPLEMENTATIONS_TS)) {
613
+ result[name] = stripTypes(code, format);
614
+ }
615
+ return result;
616
+ }
617
+ function getBlockImplementations(format = 'ts') {
618
+ const result = {};
619
+ for (const [name, code] of Object.entries(BLOCK_IMPLEMENTATIONS_TS)) {
620
+ result[name] = stripTypes(code, format);
621
+ }
622
+ return result;
623
+ }
624
+ function getAvailableCommands() {
625
+ return Object.keys(COMMAND_IMPLEMENTATIONS_TS);
626
+ }
627
+ function getAvailableBlocks() {
628
+ return Object.keys(BLOCK_IMPLEMENTATIONS_TS);
629
+ }
630
+ const COMMAND_IMPLEMENTATIONS = COMMAND_IMPLEMENTATIONS_TS;
631
+ const BLOCK_IMPLEMENTATIONS = BLOCK_IMPLEMENTATIONS_TS;
632
+
633
+ function generateBundleCode(config) {
634
+ const { name, commands, blocks = [], htmxIntegration = false, globalName = 'hyperfixi', positionalExpressions = false, parserImportPath = '../parser/hybrid', autoInit = true, esModule = true, format = 'ts', maxLoopIterations = 1000, } = config;
635
+ const needsStyleHelpers = commands.some(cmd => STYLE_COMMANDS.includes(cmd));
636
+ const needsElementArrayHelper = commands.some(cmd => ELEMENT_ARRAY_COMMANDS.includes(cmd));
637
+ const hasBlocks = blocks.length > 0;
638
+ const hasReturn = commands.includes('return');
639
+ const commandImpls = getCommandImplementations(format);
640
+ const blockImpls = getBlockImplementations(format);
641
+ const commandCases = commands
642
+ .filter(cmd => commandImpls[cmd])
643
+ .map(cmd => commandImpls[cmd])
644
+ .join('\n');
645
+ const blockCases = blocks
646
+ .filter(block => blockImpls[block])
647
+ .map(block => blockImpls[block])
648
+ .join('\n');
649
+ return `/**
650
+ * HyperFixi ${name} Bundle (Auto-Generated)
651
+ *
652
+ * Generated by: @hyperfixi/core bundle-generator
653
+ * Commands: ${commands.join(', ')}${blocks.length > 0 ? `\n * Blocks: ${blocks.join(', ')}` : ''}${positionalExpressions ? '\n * Positional expressions: enabled' : ''}
654
+ *
655
+ * DO NOT EDIT - Regenerate with the build script.
656
+ */
657
+
658
+ // =============================================================================
659
+ // MODULAR PARSER IMPORTS
660
+ // =============================================================================
661
+
662
+ import { HybridParser } from '${parserImportPath}/parser-core';
663
+ import type { ASTNode, CommandNode, EventNode${hasBlocks ? ', BlockNode' : ''} } from '${parserImportPath}/ast-types';
664
+
665
+ // =============================================================================
666
+ // RUNTIME
667
+ // =============================================================================
668
+
669
+ interface Context {
670
+ me: Element;
671
+ event?: Event;
672
+ it?: any;
673
+ you?: Element;
674
+ locals: Map<string, any>;
675
+ }
676
+
677
+ const globalVars = new Map<string, any>();
678
+ ${hasBlocks ? `const MAX_LOOP_ITERATIONS = ${maxLoopIterations};` : ''}
679
+
680
+ async function evaluate(node: ASTNode, ctx: Context): Promise<any> {
681
+ switch (node.type) {
682
+ case 'literal': return node.value;
683
+
684
+ case 'identifier':
685
+ if (node.value === 'me' || node.value === 'my') return ctx.me;
686
+ if (node.value === 'it') return ctx.it;
687
+ if (node.value === 'you') return ctx.you;
688
+ if (node.value === 'event') return ctx.event;
689
+ if (node.value === 'body') return document.body;
690
+ if (node.value === 'document') return document;
691
+ if (node.value === 'window') return window;
692
+ if (ctx.locals.has(node.value)) return ctx.locals.get(node.value);
693
+ if (node.value in (ctx.me as any)) return (ctx.me as any)[node.value];
694
+ return node.value;
695
+
696
+ case 'variable':
697
+ if (node.scope === 'local') return ctx.locals.get(node.name.slice(1));
698
+ const gName = node.name.slice(1);
699
+ if (globalVars.has(gName)) return globalVars.get(gName);
700
+ return (window as any)[node.name];
701
+
702
+ case 'selector':
703
+ const elements = document.querySelectorAll(node.value);
704
+ return elements.length === 1 ? elements[0] : Array.from(elements);
705
+
706
+ case 'binary':
707
+ return evaluateBinary(node, ctx);
708
+
709
+ case 'possessive':
710
+ case 'member':
711
+ const obj = await evaluate(node.object, ctx);
712
+ if (obj == null) return undefined;
713
+ const prop = node.computed ? await evaluate(node.property, ctx) : node.property;
714
+ return obj[prop];
715
+
716
+ case 'call': {
717
+ let callContext: any = null;
718
+ let callee: any;
719
+
720
+ if (node.callee.type === 'member' || node.callee.type === 'possessive') {
721
+ callContext = await evaluate(node.callee.object, ctx);
722
+ const p = node.callee.computed
723
+ ? await evaluate(node.callee.property, ctx)
724
+ : node.callee.property;
725
+ callee = callContext?.[p];
726
+ } else {
727
+ callee = await evaluate(node.callee, ctx);
728
+ }
729
+
730
+ const args = await Promise.all(node.args.map((a: ASTNode) => evaluate(a, ctx)));
731
+ if (typeof callee === 'function') return callee.apply(callContext, args);
732
+ return undefined;
733
+ }
734
+ ${positionalExpressions
735
+ ? `
736
+ case 'positional':
737
+ return evaluatePositional(node, ctx);
738
+ `
739
+ : ''}
740
+ default: return undefined;
741
+ }
742
+ }
743
+
744
+ async function evaluateBinary(node: ASTNode, ctx: Context): Promise<any> {
745
+ if (node.operator === 'has') {
746
+ const left = await evaluate(node.left, ctx);
747
+ if (left instanceof Element && node.right.type === 'selector' && node.right.value.startsWith('.')) {
748
+ return left.classList.contains(node.right.value.slice(1));
749
+ }
750
+ return false;
751
+ }
752
+
753
+ const left = await evaluate(node.left, ctx);
754
+ const right = await evaluate(node.right, ctx);
755
+
756
+ switch (node.operator) {
757
+ case '+': return left + right;
758
+ case '-': return left - right;
759
+ case '*': return left * right;
760
+ case '/': return left / right;
761
+ case '%': return left % right;
762
+ case '==': case 'is': return left == right;
763
+ case '!=': case 'is not': return left != right;
764
+ case '<': return left < right;
765
+ case '>': return left > right;
766
+ case '<=': return left <= right;
767
+ case '>=': return left >= right;
768
+ case 'and': case '&&': return left && right;
769
+ case 'or': case '||': return left || right;
770
+ case 'contains': case 'includes':
771
+ if (typeof left === 'string') return left.includes(right);
772
+ if (Array.isArray(left)) return left.includes(right);
773
+ if (left instanceof Element) return left.contains(right);
774
+ return false;
775
+ case 'matches':
776
+ if (left instanceof Element) return left.matches(right);
777
+ if (typeof left === 'string') return new RegExp(right).test(left);
778
+ return false;
779
+ default: return undefined;
780
+ }
781
+ }
782
+ ${positionalExpressions
783
+ ? `
784
+ function evaluatePositional(node: ASTNode, ctx: Context): Element | null {
785
+ const target = node.target;
786
+ let elements: Element[] = [];
787
+
788
+ let selector: string | null = null;
789
+ if (target.type === 'selector') {
790
+ selector = target.value;
791
+ } else if (target.type === 'identifier') {
792
+ selector = target.value;
793
+ } else if (target.type === 'htmlSelector') {
794
+ selector = target.value;
795
+ }
796
+ if (selector) {
797
+ elements = Array.from(document.querySelectorAll(selector));
798
+ }
799
+
800
+ switch (node.position) {
801
+ case 'first': return elements[0] || null;
802
+ case 'last': return elements[elements.length - 1] || null;
803
+ case 'next': return ctx.me.nextElementSibling;
804
+ case 'previous': return ctx.me.previousElementSibling;
805
+ case 'closest': return target.value ? ctx.me.closest(target.value) : null;
806
+ case 'parent': return ctx.me.parentElement;
807
+ default: return elements[0] || null;
808
+ }
809
+ }
810
+ `
811
+ : ''}
812
+ // =============================================================================
813
+ // COMMAND EXECUTOR
814
+ // =============================================================================
815
+
816
+ ${needsStyleHelpers
817
+ ? `
818
+ const isStyleProp = (prop: string) => prop?.startsWith('*');
819
+ const getStyleName = (prop: string) => prop.substring(1);
820
+ const setStyleProp = (el: Element, prop: string, value: any): boolean => {
821
+ if (!isStyleProp(prop)) return false;
822
+ (el as HTMLElement).style.setProperty(getStyleName(prop), String(value));
823
+ return true;
824
+ };
825
+ `
826
+ : ''}
827
+
828
+ ${needsElementArrayHelper
829
+ ? `
830
+ const toElementArray = (val: any): Element[] => {
831
+ if (Array.isArray(val)) return val.filter(e => e instanceof Element);
832
+ if (val instanceof Element) return [val];
833
+ if (typeof val === 'string') return Array.from(document.querySelectorAll(val));
834
+ return [];
835
+ };
836
+ `
837
+ : ''}
838
+
839
+ async function executeCommand(cmd: CommandNode, ctx: Context): Promise<any> {
840
+ const getTarget = async (): Promise<Element[]> => {
841
+ if (!cmd.target) return [ctx.me];
842
+ const t = await evaluate(cmd.target, ctx);
843
+ if (Array.isArray(t)) return t;
844
+ if (t instanceof Element) return [t];
845
+ if (typeof t === 'string') return Array.from(document.querySelectorAll(t));
846
+ return [ctx.me];
847
+ };
848
+
849
+ const getClassName = (node: any): string => {
850
+ if (!node) return '';
851
+ if (node.type === 'selector') return node.value.slice(1);
852
+ if (node.type === 'string' || node.type === 'literal') {
853
+ const val = node.value;
854
+ return typeof val === 'string' && val.startsWith('.') ? val.slice(1) : String(val);
855
+ }
856
+ if (node.type === 'identifier') return node.value;
857
+ return '';
858
+ };
859
+
860
+ switch (cmd.name) {
861
+ ${commandCases}
862
+
863
+ default:
864
+ console.warn(\`${name} bundle: Unknown command '\${cmd.name}'\`);
865
+ return null;
866
+ }
867
+ }
868
+ ${hasBlocks
869
+ ? `
870
+ // =============================================================================
871
+ // BLOCK EXECUTOR
872
+ // =============================================================================
873
+
874
+ async function executeBlock(block: BlockNode, ctx: Context): Promise<any> {
875
+ switch (block.type) {
876
+ ${blockCases}
877
+
878
+ default:
879
+ console.warn(\`${name} bundle: Unknown block '\${block.type}'\`);
880
+ return null;
881
+ }
882
+ }
883
+ `
884
+ : ''}
885
+ // =============================================================================
886
+ // SEQUENCE EXECUTOR
887
+ // =============================================================================
888
+
889
+ async function executeSequence(nodes: ASTNode[], ctx: Context): Promise<any> {
890
+ let result: any;
891
+ for (const node of nodes) {
892
+ if (node.type === 'command') {
893
+ result = await executeCommand(node as CommandNode, ctx);
894
+ }${hasBlocks
895
+ ? ` else if (['if', 'repeat', 'for', 'while', 'fetch'].includes(node.type)) {
896
+ result = await executeBlock(node as BlockNode, ctx);
897
+ }`
898
+ : ''}
899
+ }
900
+ return result;
901
+ }
902
+ ${hasBlocks
903
+ ? `
904
+ async function executeSequenceWithBlocks(nodes: ASTNode[], ctx: Context): Promise<any> {
905
+ try {
906
+ return await executeSequence(nodes, ctx);
907
+ } catch (e: any) {
908
+ if (e?.type === 'return') throw e;
909
+ throw e;
910
+ }
911
+ }
912
+ `
913
+ : ''}
914
+ async function executeAST(ast: ASTNode, me: Element, event?: Event): Promise<any> {
915
+ const ctx: Context = { me, event, locals: new Map() };
916
+
917
+ if (ast.type === 'sequence') {
918
+ ${hasReturn || hasBlocks ? "try { return await executeSequence(ast.commands, ctx); } catch (e: any) { if (e?.type === 'return') return e.value; throw e; }" : 'return executeSequence(ast.commands, ctx);'}
919
+ }
920
+
921
+ if (ast.type === 'event') {
922
+ const eventNode = ast as EventNode;
923
+ const eventName = eventNode.event;
924
+
925
+ if (eventName === 'init') {
926
+ ${hasReturn || hasBlocks ? "try { await executeSequence(eventNode.body, ctx); } catch (e: any) { if (e?.type !== 'return') throw e; }" : 'await executeSequence(eventNode.body, ctx);'}
927
+ return;
928
+ }
929
+
930
+ const target = eventNode.filter ? await evaluate(eventNode.filter, ctx) : me;
931
+ const targetEl = target instanceof Element ? target : me;
932
+ const mods = eventNode.modifiers;
933
+
934
+ let handler = async (e: Event) => {
935
+ if (mods.prevent) e.preventDefault();
936
+ if (mods.stop) e.stopPropagation();
937
+
938
+ const handlerCtx: Context = {
939
+ me, event: e,
940
+ you: e.target instanceof Element ? e.target : undefined,
941
+ locals: new Map(),
942
+ };
943
+ ${hasReturn || hasBlocks ? "try { await executeSequence(eventNode.body, handlerCtx); } catch (err: any) { if (err?.type !== 'return') throw err; }" : 'await executeSequence(eventNode.body, handlerCtx);'}
944
+ };
945
+
946
+ if (mods.debounce) {
947
+ let timeout: any;
948
+ const orig = handler;
949
+ handler = async (e: Event) => {
950
+ clearTimeout(timeout);
951
+ timeout = setTimeout(() => orig(e), mods.debounce);
952
+ };
953
+ }
954
+
955
+ if (mods.throttle) {
956
+ let lastCall = 0;
957
+ const orig = handler;
958
+ handler = async (e: Event) => {
959
+ const now = Date.now();
960
+ if (now - lastCall >= mods.throttle!) {
961
+ lastCall = now;
962
+ await orig(e);
963
+ }
964
+ };
965
+ }
966
+
967
+ targetEl.addEventListener(eventName, handler, { once: !!mods.once });
968
+ return;
969
+ }
970
+
971
+ return null;
972
+ }
973
+
974
+ // =============================================================================
975
+ // DOM PROCESSOR
976
+ // =============================================================================
977
+
978
+ function processElement(el: Element): void {
979
+ const code = el.getAttribute('_');
980
+ if (!code) return;
981
+
982
+ try {
983
+ const parser = new HybridParser(code);
984
+ const ast = parser.parse();
985
+ executeAST(ast, el);
986
+ } catch (err) {
987
+ console.error('HyperFixi ${name} error:', err, 'Code:', code);
988
+ }
989
+ }
990
+
991
+ function processElements(root: Element | Document = document): void {
992
+ const elements = root.querySelectorAll('[_]');
993
+ elements.forEach(processElement);
994
+ }
995
+
996
+ // =============================================================================
997
+ // PUBLIC API
998
+ // =============================================================================
999
+
1000
+ const api = {
1001
+ version: '1.0.0-${name.toLowerCase().replace(/\s+/g, '-')}',
1002
+
1003
+ parse(code: string): ASTNode {
1004
+ const parser = new HybridParser(code);
1005
+ return parser.parse();
1006
+ },
1007
+
1008
+ async execute(code: string, element?: Element): Promise<any> {
1009
+ const me = element || document.body;
1010
+ const parser = new HybridParser(code);
1011
+ const ast = parser.parse();
1012
+ return executeAST(ast, me);
1013
+ },
1014
+
1015
+ run: async (code: string, element?: Element) => api.execute(code, element),
1016
+ eval: async (code: string, element?: Element) => api.execute(code, element),
1017
+
1018
+ init: processElements,
1019
+ process: processElements,
1020
+
1021
+ commands: ${JSON.stringify(commands)},
1022
+ ${blocks.length > 0 ? `blocks: ${JSON.stringify(blocks)},` : ''}
1023
+ parserName: 'hybrid',
1024
+ };
1025
+
1026
+ // =============================================================================
1027
+ // AUTO-INITIALIZE
1028
+ // =============================================================================
1029
+ ${autoInit
1030
+ ? `
1031
+ if (typeof window !== 'undefined') {
1032
+ (window as any).${globalName} = api;
1033
+ (window as any)._hyperscript = api;
1034
+
1035
+ if (document.readyState === 'loading') {
1036
+ document.addEventListener('DOMContentLoaded', () => processElements());
1037
+ } else {
1038
+ processElements();
1039
+ }
1040
+ ${htmxIntegration
1041
+ ? `
1042
+ // HTMX integration
1043
+ document.addEventListener('htmx:afterSettle', (e: Event) => {
1044
+ const target = (e as CustomEvent).detail?.target;
1045
+ if (target) processElements(target);
1046
+ });
1047
+ `
1048
+ : ''}
1049
+ }
1050
+ `
1051
+ : ''}
1052
+ ${esModule
1053
+ ? `
1054
+ export default api;
1055
+ export { api, processElements };
1056
+ `
1057
+ : ''}`;
1058
+ }
1059
+ function generateBundle(config) {
1060
+ const warnings = [];
1061
+ const errors = [];
1062
+ const strict = config.validation?.strict ?? false;
1063
+ const unknownCommands = config.commands.filter(cmd => !COMMAND_IMPLEMENTATIONS[cmd]);
1064
+ for (const cmd of unknownCommands) {
1065
+ const error = {
1066
+ type: 'unknown-command',
1067
+ message: `Unknown command '${cmd}' will not be included`,
1068
+ name: cmd,
1069
+ };
1070
+ errors.push(error);
1071
+ warnings.push(error.message);
1072
+ }
1073
+ const unknownBlocks = (config.blocks || []).filter(block => !BLOCK_IMPLEMENTATIONS[block]);
1074
+ for (const block of unknownBlocks) {
1075
+ const error = {
1076
+ type: 'unknown-block',
1077
+ message: `Unknown block '${block}' will not be included`,
1078
+ name: block,
1079
+ };
1080
+ errors.push(error);
1081
+ warnings.push(error.message);
1082
+ }
1083
+ if (strict && errors.length > 0) {
1084
+ const errorMessages = errors.map(e => e.message).join('; ');
1085
+ throw new Error(`Bundle generation failed (strict mode): ${errorMessages}`);
1086
+ }
1087
+ const code = generateBundleCode(config);
1088
+ return {
1089
+ code,
1090
+ commands: config.commands.filter(cmd => COMMAND_IMPLEMENTATIONS[cmd]),
1091
+ blocks: (config.blocks || []).filter(block => BLOCK_IMPLEMENTATIONS[block]),
1092
+ positional: config.positionalExpressions || false,
1093
+ warnings,
1094
+ errors,
1095
+ };
1096
+ }
1097
+
1098
+ const LITE_PARSER_TEMPLATE = `
1099
+ // Lite Parser - Regex-based for minimal bundle size
1100
+
1101
+ function parseLite(code) {
1102
+ const trimmed = code.trim();
1103
+
1104
+ // Handle event handlers: "on click toggle .active"
1105
+ const onMatch = trimmed.match(/^on\\s+(\\w+)(?:\\s+from\\s+([^\\s]+))?\\s+(.+)$/i);
1106
+ if (onMatch) {
1107
+ return {
1108
+ type: 'event',
1109
+ event: onMatch[1],
1110
+ filter: onMatch[2] ? { type: 'selector', value: onMatch[2] } : undefined,
1111
+ modifiers: {},
1112
+ body: parseCommands(onMatch[3]),
1113
+ };
1114
+ }
1115
+
1116
+ // Handle "every Nms" event pattern
1117
+ const everyMatch = trimmed.match(/^every\\s+(\\d+)(ms|s)?\\s+(.+)$/i);
1118
+ if (everyMatch) {
1119
+ const ms = everyMatch[2] === 's' ? parseInt(everyMatch[1]) * 1000 : parseInt(everyMatch[1]);
1120
+ return {
1121
+ type: 'event',
1122
+ event: 'interval:' + ms,
1123
+ modifiers: {},
1124
+ body: parseCommands(everyMatch[3]),
1125
+ };
1126
+ }
1127
+
1128
+ // Handle "init" pattern
1129
+ const initMatch = trimmed.match(/^init\\s+(.+)$/i);
1130
+ if (initMatch) {
1131
+ return {
1132
+ type: 'event',
1133
+ event: 'init',
1134
+ modifiers: {},
1135
+ body: parseCommands(initMatch[1]),
1136
+ };
1137
+ }
1138
+
1139
+ return { type: 'sequence', commands: parseCommands(trimmed) };
1140
+ }
1141
+
1142
+ function parseCommands(code) {
1143
+ const parts = code.split(/\\s+(?:then|and)\\s+/i);
1144
+ return parts.map(parseCommand).filter(Boolean);
1145
+ }
1146
+
1147
+ function parseCommand(code) {
1148
+ const trimmed = code.trim();
1149
+ if (!trimmed) return null;
1150
+
1151
+ let match;
1152
+
1153
+ // toggle .class [on target]
1154
+ match = trimmed.match(/^toggle\\s+(\\.\\w+|\\w+)(?:\\s+on\\s+(.+))?$/i);
1155
+ if (match) {
1156
+ return {
1157
+ type: 'command',
1158
+ name: 'toggle',
1159
+ args: [{ type: 'selector', value: match[1] }],
1160
+ target: match[2] ? parseTarget(match[2]) : undefined,
1161
+ };
1162
+ }
1163
+
1164
+ // add .class [to target]
1165
+ match = trimmed.match(/^add\\s+(\\.\\w+|\\w+)(?:\\s+to\\s+(.+))?$/i);
1166
+ if (match) {
1167
+ return {
1168
+ type: 'command',
1169
+ name: 'add',
1170
+ args: [{ type: 'selector', value: match[1] }],
1171
+ target: match[2] ? parseTarget(match[2]) : undefined,
1172
+ };
1173
+ }
1174
+
1175
+ // remove .class [from target] | remove [target]
1176
+ match = trimmed.match(/^remove\\s+(\\.\\w+)(?:\\s+from\\s+(.+))?$/i);
1177
+ if (match) {
1178
+ return {
1179
+ type: 'command',
1180
+ name: 'removeClass',
1181
+ args: [{ type: 'selector', value: match[1] }],
1182
+ target: match[2] ? parseTarget(match[2]) : undefined,
1183
+ };
1184
+ }
1185
+ match = trimmed.match(/^remove\\s+(.+)$/i);
1186
+ if (match) {
1187
+ return {
1188
+ type: 'command',
1189
+ name: 'remove',
1190
+ args: [],
1191
+ target: parseTarget(match[1]),
1192
+ };
1193
+ }
1194
+
1195
+ // put "content" into target
1196
+ match = trimmed.match(/^put\\s+(?:"([^"]+)"|'([^']+)'|(\\S+))\\s+(into|before|after)\\s+(.+)$/i);
1197
+ if (match) {
1198
+ const content = match[1] || match[2] || match[3];
1199
+ return {
1200
+ type: 'command',
1201
+ name: 'put',
1202
+ args: [{ type: 'literal', value: content }],
1203
+ modifier: match[4],
1204
+ target: parseTarget(match[5]),
1205
+ };
1206
+ }
1207
+
1208
+ // set target to value | set :var to value
1209
+ match = trimmed.match(/^set\\s+(.+?)\\s+to\\s+(.+)$/i);
1210
+ if (match) {
1211
+ return {
1212
+ type: 'command',
1213
+ name: 'set',
1214
+ args: [parseTarget(match[1]), parseLiteValue(match[2])],
1215
+ };
1216
+ }
1217
+
1218
+ // log message
1219
+ match = trimmed.match(/^log\\s+(.+)$/i);
1220
+ if (match) {
1221
+ return {
1222
+ type: 'command',
1223
+ name: 'log',
1224
+ args: [parseLiteValue(match[1])],
1225
+ };
1226
+ }
1227
+
1228
+ // send event [to target]
1229
+ match = trimmed.match(/^send\\s+(\\w+)(?:\\s+to\\s+(.+))?$/i);
1230
+ if (match) {
1231
+ return {
1232
+ type: 'command',
1233
+ name: 'send',
1234
+ args: [{ type: 'literal', value: match[1] }],
1235
+ target: match[2] ? parseTarget(match[2]) : undefined,
1236
+ };
1237
+ }
1238
+
1239
+ // wait Nms | wait Ns
1240
+ match = trimmed.match(/^wait\\s+(\\d+)(ms|s)?$/i);
1241
+ if (match) {
1242
+ const ms = match[2] === 's' ? parseInt(match[1]) * 1000 : parseInt(match[1]);
1243
+ return {
1244
+ type: 'command',
1245
+ name: 'wait',
1246
+ args: [{ type: 'literal', value: ms }],
1247
+ };
1248
+ }
1249
+
1250
+ // show/hide shortcuts
1251
+ match = trimmed.match(/^(show|hide)(?:\\s+(.+))?$/i);
1252
+ if (match) {
1253
+ return {
1254
+ type: 'command',
1255
+ name: match[1].toLowerCase(),
1256
+ args: [],
1257
+ target: match[2] ? parseTarget(match[2]) : undefined,
1258
+ };
1259
+ }
1260
+
1261
+ // Unknown command - try generic parsing
1262
+ const parts = trimmed.split(/\\s+/);
1263
+ if (parts.length > 0) {
1264
+ return {
1265
+ type: 'command',
1266
+ name: parts[0],
1267
+ args: parts.slice(1).map(p => ({ type: 'literal', value: p })),
1268
+ };
1269
+ }
1270
+
1271
+ return null;
1272
+ }
1273
+
1274
+ function parseTarget(str) {
1275
+ const s = str.trim();
1276
+ if (s === 'me') return { type: 'identifier', value: 'me' };
1277
+ if (s === 'body') return { type: 'identifier', value: 'body' };
1278
+ if (s.startsWith('#') || s.startsWith('.') || s.startsWith('[')) {
1279
+ return { type: 'selector', value: s };
1280
+ }
1281
+ if (s.startsWith(':')) {
1282
+ return { type: 'variable', name: s, scope: 'local' };
1283
+ }
1284
+ return { type: 'identifier', value: s };
1285
+ }
1286
+
1287
+ function parseLiteValue(str) {
1288
+ const s = str.trim();
1289
+ if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
1290
+ return { type: 'literal', value: s.slice(1, -1) };
1291
+ }
1292
+ if (/^-?\\d+(\\.\\d+)?$/.test(s)) {
1293
+ return { type: 'literal', value: parseFloat(s) };
1294
+ }
1295
+ if (s === 'true') return { type: 'literal', value: true };
1296
+ if (s === 'false') return { type: 'literal', value: false };
1297
+ if (s === 'null') return { type: 'literal', value: null };
1298
+ if (s.startsWith(':')) return { type: 'variable', name: s, scope: 'local' };
1299
+ if (s === 'me') return { type: 'identifier', value: 'me' };
1300
+ return { type: 'identifier', value: s };
1301
+ }
1302
+ `;
1303
+ const HYBRID_PARSER_TEMPLATE = `
1304
+ // Hybrid Parser - Full AST with operator precedence
1305
+
1306
+ // Tokenizer
1307
+ const KEYWORDS = new Set([
1308
+ 'on', 'from', 'to', 'into', 'before', 'after', 'in', 'of', 'at', 'with',
1309
+ 'if', 'else', 'unless', 'end', 'then', 'and', 'or', 'not',
1310
+ 'repeat', 'times', 'for', 'each', 'while', 'until',
1311
+ 'toggle', 'add', 'remove', 'put', 'set', 'get', 'call', 'return', 'append',
1312
+ 'log', 'send', 'trigger', 'wait', 'settle', 'fetch', 'as',
1313
+ 'show', 'hide', 'take', 'increment', 'decrement', 'focus', 'blur', 'go', 'transition', 'over',
1314
+ 'the', 'a', 'an', 'my', 'its', 'me', 'it', 'you',
1315
+ 'first', 'last', 'next', 'previous', 'closest', 'parent',
1316
+ 'true', 'false', 'null', 'undefined',
1317
+ 'is', 'matches', 'contains', 'includes', 'exists', 'has', 'init', 'every', 'by',
1318
+ ]);
1319
+
1320
+ const COMMAND_ALIASES = {
1321
+ flip: 'toggle', switch: 'toggle', display: 'show', reveal: 'show',
1322
+ conceal: 'hide', increase: 'increment', decrease: 'decrement',
1323
+ fire: 'trigger', dispatch: 'send', navigate: 'go', goto: 'go',
1324
+ };
1325
+
1326
+ const EVENT_ALIASES = {
1327
+ clicked: 'click', pressed: 'keydown', changed: 'change',
1328
+ submitted: 'submit', loaded: 'load',
1329
+ };
1330
+
1331
+ function normalizeCommand(name) {
1332
+ const lower = name.toLowerCase();
1333
+ return COMMAND_ALIASES[lower] || lower;
1334
+ }
1335
+
1336
+ function normalizeEvent(name) {
1337
+ const lower = name.toLowerCase();
1338
+ return EVENT_ALIASES[lower] || lower;
1339
+ }
1340
+
1341
+ function tokenize(code) {
1342
+ const tokens = [];
1343
+ let pos = 0;
1344
+
1345
+ while (pos < code.length) {
1346
+ if (/\\s/.test(code[pos])) { pos++; continue; }
1347
+ if (code.slice(pos, pos + 2) === '--') {
1348
+ while (pos < code.length && code[pos] !== '\\n') pos++;
1349
+ continue;
1350
+ }
1351
+
1352
+ const start = pos;
1353
+
1354
+ // HTML selector <tag/>
1355
+ if (code[pos] === '<' && /[a-zA-Z]/.test(code[pos + 1] || '')) {
1356
+ pos++;
1357
+ while (pos < code.length && code[pos] !== '>') pos++;
1358
+ if (code[pos] === '>') pos++;
1359
+ const val = code.slice(start, pos);
1360
+ if (val.endsWith('/>') || val.endsWith('>')) {
1361
+ const normalized = val.slice(1).replace(/\\/?>$/, '');
1362
+ tokens.push({ type: 'selector', value: normalized, pos: start });
1363
+ continue;
1364
+ }
1365
+ }
1366
+
1367
+ // Possessive 's
1368
+ if (code.slice(pos, pos + 2) === "'s" && !/[a-zA-Z]/.test(code[pos + 2] || '')) {
1369
+ tokens.push({ type: 'operator', value: "'s", pos: start });
1370
+ pos += 2;
1371
+ continue;
1372
+ }
1373
+
1374
+ // String literals
1375
+ if (code[pos] === '"' || code[pos] === "'") {
1376
+ const quote = code[pos++];
1377
+ while (pos < code.length && code[pos] !== quote) {
1378
+ if (code[pos] === '\\\\') pos++;
1379
+ pos++;
1380
+ }
1381
+ pos++;
1382
+ tokens.push({ type: 'string', value: code.slice(start, pos), pos: start });
1383
+ continue;
1384
+ }
1385
+
1386
+ // Numbers with units
1387
+ if (/\\d/.test(code[pos]) || (code[pos] === '-' && /\\d/.test(code[pos + 1] || ''))) {
1388
+ if (code[pos] === '-') pos++;
1389
+ while (pos < code.length && /[\\d.]/.test(code[pos])) pos++;
1390
+ if (code.slice(pos, pos + 2) === 'ms') pos += 2;
1391
+ else if (code[pos] === 's' && !/[a-zA-Z]/.test(code[pos + 1] || '')) pos++;
1392
+ else if (code.slice(pos, pos + 2) === 'px') pos += 2;
1393
+ tokens.push({ type: 'number', value: code.slice(start, pos), pos: start });
1394
+ continue;
1395
+ }
1396
+
1397
+ // Local variable :name
1398
+ if (code[pos] === ':') {
1399
+ pos++;
1400
+ while (pos < code.length && /[\\w]/.test(code[pos])) pos++;
1401
+ tokens.push({ type: 'localVar', value: code.slice(start, pos), pos: start });
1402
+ continue;
1403
+ }
1404
+
1405
+ // Global variable $name
1406
+ if (code[pos] === '$') {
1407
+ pos++;
1408
+ while (pos < code.length && /[\\w]/.test(code[pos])) pos++;
1409
+ tokens.push({ type: 'globalVar', value: code.slice(start, pos), pos: start });
1410
+ continue;
1411
+ }
1412
+
1413
+ // CSS selectors: #id, .class
1414
+ if (code[pos] === '#' || code[pos] === '.') {
1415
+ if (code[pos] === '.') {
1416
+ const afterDot = code.slice(pos + 1).match(/^(once|prevent|stop|debounce|throttle)\\b/i);
1417
+ if (afterDot) {
1418
+ tokens.push({ type: 'symbol', value: '.', pos: start });
1419
+ pos++;
1420
+ continue;
1421
+ }
1422
+ }
1423
+ pos++;
1424
+ while (pos < code.length && /[\\w-]/.test(code[pos])) pos++;
1425
+ tokens.push({ type: 'selector', value: code.slice(start, pos), pos: start });
1426
+ continue;
1427
+ }
1428
+
1429
+ // Array literal vs Attribute selector
1430
+ if (code[pos] === '[') {
1431
+ let lookahead = pos + 1;
1432
+ while (lookahead < code.length && /\\s/.test(code[lookahead])) lookahead++;
1433
+ const nextChar = code[lookahead] || '';
1434
+ const isArrayLiteral = /['"\\d\\[\\]:\\$\\-]/.test(nextChar) || nextChar === '';
1435
+ if (isArrayLiteral) {
1436
+ tokens.push({ type: 'symbol', value: '[', pos: start });
1437
+ pos++;
1438
+ continue;
1439
+ } else {
1440
+ pos++;
1441
+ let depth = 1;
1442
+ while (pos < code.length && depth > 0) {
1443
+ if (code[pos] === '[') depth++;
1444
+ if (code[pos] === ']') depth--;
1445
+ pos++;
1446
+ }
1447
+ tokens.push({ type: 'selector', value: code.slice(start, pos), pos: start });
1448
+ continue;
1449
+ }
1450
+ }
1451
+
1452
+ if (code[pos] === ']') {
1453
+ tokens.push({ type: 'symbol', value: ']', pos: start });
1454
+ pos++;
1455
+ continue;
1456
+ }
1457
+
1458
+ // Multi-char operators
1459
+ const twoChar = code.slice(pos, pos + 2);
1460
+ if (['==', '!=', '<=', '>=', '&&', '||'].includes(twoChar)) {
1461
+ tokens.push({ type: 'operator', value: twoChar, pos: start });
1462
+ pos += 2;
1463
+ continue;
1464
+ }
1465
+
1466
+ // Style property *opacity
1467
+ if (code[pos] === '*' && /[a-zA-Z]/.test(code[pos + 1] || '')) {
1468
+ pos++;
1469
+ while (pos < code.length && /[\\w-]/.test(code[pos])) pos++;
1470
+ tokens.push({ type: 'styleProperty', value: code.slice(start, pos), pos: start });
1471
+ continue;
1472
+ }
1473
+
1474
+ if ('+-*/%<>!'.includes(code[pos])) {
1475
+ tokens.push({ type: 'operator', value: code[pos], pos: start });
1476
+ pos++;
1477
+ continue;
1478
+ }
1479
+
1480
+ if ('()[]{},.'.includes(code[pos])) {
1481
+ tokens.push({ type: 'symbol', value: code[pos], pos: start });
1482
+ pos++;
1483
+ continue;
1484
+ }
1485
+
1486
+ if (/[a-zA-Z_]/.test(code[pos])) {
1487
+ while (pos < code.length && /[\\w-]/.test(code[pos])) pos++;
1488
+ const value = code.slice(start, pos);
1489
+ const type = KEYWORDS.has(value.toLowerCase()) ? 'keyword' : 'identifier';
1490
+ tokens.push({ type, value, pos: start });
1491
+ continue;
1492
+ }
1493
+
1494
+ pos++;
1495
+ }
1496
+
1497
+ tokens.push({ type: 'eof', value: '', pos: code.length });
1498
+ return tokens;
1499
+ }
1500
+
1501
+ // Parser
1502
+ class HybridParser {
1503
+ constructor(code) {
1504
+ this.tokens = tokenize(code);
1505
+ this.pos = 0;
1506
+ }
1507
+
1508
+ peek(offset = 0) {
1509
+ return this.tokens[Math.min(this.pos + offset, this.tokens.length - 1)];
1510
+ }
1511
+
1512
+ advance() {
1513
+ return this.tokens[this.pos++];
1514
+ }
1515
+
1516
+ match(...values) {
1517
+ const token = this.peek();
1518
+ return values.some(v => token.value.toLowerCase() === v.toLowerCase());
1519
+ }
1520
+
1521
+ matchType(...types) {
1522
+ return types.includes(this.peek().type);
1523
+ }
1524
+
1525
+ expect(value) {
1526
+ if (!this.match(value) && normalizeCommand(this.peek().value) !== value) {
1527
+ throw new Error("Expected '" + value + "', got '" + this.peek().value + "'");
1528
+ }
1529
+ return this.advance();
1530
+ }
1531
+
1532
+ isAtEnd() {
1533
+ return this.peek().type === 'eof';
1534
+ }
1535
+
1536
+ parse() {
1537
+ if (this.match('on')) return this.parseEventHandler();
1538
+ if (this.match('init')) {
1539
+ this.advance();
1540
+ return { type: 'event', event: 'init', modifiers: {}, body: this.parseCommandSequence() };
1541
+ }
1542
+ if (this.match('every')) return this.parseEveryHandler();
1543
+ return { type: 'sequence', commands: this.parseCommandSequence() };
1544
+ }
1545
+
1546
+ parseEventHandler() {
1547
+ this.expect('on');
1548
+ const eventName = this.advance().value;
1549
+ const modifiers = {};
1550
+ let filter;
1551
+
1552
+ while (this.peek().value === '.') {
1553
+ this.advance();
1554
+ const mod = this.advance().value.toLowerCase();
1555
+ if (mod === 'once') modifiers.once = true;
1556
+ else if (mod === 'prevent') modifiers.prevent = true;
1557
+ else if (mod === 'stop') modifiers.stop = true;
1558
+ else if (mod === 'debounce' || mod === 'throttle') {
1559
+ if (this.peek().value === '(') {
1560
+ this.advance();
1561
+ const num = this.advance().value;
1562
+ this.expect(')');
1563
+ if (mod === 'debounce') modifiers.debounce = parseInt(num) || 100;
1564
+ else modifiers.throttle = parseInt(num) || 100;
1565
+ }
1566
+ }
1567
+ }
1568
+
1569
+ if (this.match('from')) {
1570
+ this.advance();
1571
+ filter = this.parseExpression();
1572
+ }
1573
+
1574
+ return { type: 'event', event: normalizeEvent(eventName), filter, modifiers, body: this.parseCommandSequence() };
1575
+ }
1576
+
1577
+ parseEveryHandler() {
1578
+ this.expect('every');
1579
+ const interval = this.advance().value;
1580
+ return { type: 'event', event: 'interval:' + interval, modifiers: {}, body: this.parseCommandSequence() };
1581
+ }
1582
+
1583
+ parseCommandSequence() {
1584
+ const commands = [];
1585
+ while (!this.isAtEnd() && !this.match('end', 'else')) {
1586
+ const cmd = this.parseCommand();
1587
+ if (cmd) commands.push(cmd);
1588
+ if (this.match('then', 'and')) this.advance();
1589
+ }
1590
+ return commands;
1591
+ }
1592
+
1593
+ parseCommand() {
1594
+ if (this.match('if', 'unless')) return this.parseIf();
1595
+ if (this.match('repeat')) return this.parseRepeat();
1596
+ if (this.match('for')) return this.parseFor();
1597
+ if (this.match('while')) return this.parseWhile();
1598
+ if (this.match('fetch')) return this.parseFetchBlock();
1599
+
1600
+ const cmdMap = {
1601
+ toggle: () => this.parseToggle(),
1602
+ add: () => this.parseAdd(),
1603
+ remove: () => this.parseRemove(),
1604
+ put: () => this.parsePut(),
1605
+ append: () => this.parseAppend(),
1606
+ set: () => this.parseSet(),
1607
+ get: () => this.parseGet(),
1608
+ call: () => this.parseCall(),
1609
+ log: () => this.parseLog(),
1610
+ send: () => this.parseSend(),
1611
+ trigger: () => this.parseSend(),
1612
+ wait: () => this.parseWait(),
1613
+ show: () => this.parseShow(),
1614
+ hide: () => this.parseHide(),
1615
+ take: () => this.parseTake(),
1616
+ increment: () => this.parseIncDec('increment'),
1617
+ decrement: () => this.parseIncDec('decrement'),
1618
+ focus: () => this.parseFocusBlur('focus'),
1619
+ blur: () => this.parseFocusBlur('blur'),
1620
+ go: () => this.parseGo(),
1621
+ return: () => this.parseReturn(),
1622
+ transition: () => this.parseTransition(),
1623
+ };
1624
+
1625
+ const normalized = normalizeCommand(this.peek().value);
1626
+ if (cmdMap[normalized]) return cmdMap[normalized]();
1627
+
1628
+ if (!this.isAtEnd() && !this.match('then', 'and', 'end', 'else')) this.advance();
1629
+ return null;
1630
+ }
1631
+
1632
+ parseIf() {
1633
+ const isUnless = this.match('unless');
1634
+ this.advance();
1635
+ const condition = this.parseExpression();
1636
+ const body = this.parseCommandSequence();
1637
+ let elseBody;
1638
+
1639
+ if (this.match('else')) {
1640
+ this.advance();
1641
+ elseBody = this.parseCommandSequence();
1642
+ }
1643
+ if (this.match('end')) this.advance();
1644
+
1645
+ return {
1646
+ type: 'if',
1647
+ condition: isUnless ? { type: 'unary', operator: 'not', operand: condition } : condition,
1648
+ body,
1649
+ elseBody,
1650
+ };
1651
+ }
1652
+
1653
+ parseRepeat() {
1654
+ this.expect('repeat');
1655
+ let count;
1656
+ if (!this.match('until', 'while', 'forever')) {
1657
+ count = this.parseExpression();
1658
+ if (this.match('times')) this.advance();
1659
+ }
1660
+ const body = this.parseCommandSequence();
1661
+ if (this.match('end')) this.advance();
1662
+ return { type: 'repeat', condition: count, body };
1663
+ }
1664
+
1665
+ parseFor() {
1666
+ this.expect('for');
1667
+ if (this.match('each')) this.advance();
1668
+ const variable = this.advance().value;
1669
+ this.expect('in');
1670
+ const iterable = this.parseExpression();
1671
+ const body = this.parseCommandSequence();
1672
+ if (this.match('end')) this.advance();
1673
+ return { type: 'for', condition: { type: 'forCondition', variable, iterable }, body };
1674
+ }
1675
+
1676
+ parseWhile() {
1677
+ this.expect('while');
1678
+ const condition = this.parseExpression();
1679
+ const body = this.parseCommandSequence();
1680
+ if (this.match('end')) this.advance();
1681
+ return { type: 'while', condition, body };
1682
+ }
1683
+
1684
+ parseFetchBlock() {
1685
+ this.expect('fetch');
1686
+ const url = this.parseExpression();
1687
+ let responseType = { type: 'literal', value: 'text' };
1688
+ if (this.match('as')) {
1689
+ this.advance();
1690
+ responseType = this.parseExpression();
1691
+ }
1692
+ if (this.match('then')) this.advance();
1693
+ const body = this.parseCommandSequence();
1694
+ return { type: 'fetch', condition: { type: 'fetchConfig', url, responseType }, body };
1695
+ }
1696
+
1697
+ parseToggle() {
1698
+ this.expect('toggle');
1699
+ const what = this.parseExpression();
1700
+ let target;
1701
+ if (this.match('on')) {
1702
+ this.advance();
1703
+ target = this.parseExpression();
1704
+ }
1705
+ return { type: 'command', name: 'toggle', args: [what], target };
1706
+ }
1707
+
1708
+ parseAdd() {
1709
+ this.expect('add');
1710
+ const what = this.parseExpression();
1711
+ let target;
1712
+ if (this.match('to')) {
1713
+ this.advance();
1714
+ target = this.parseExpression();
1715
+ }
1716
+ return { type: 'command', name: 'add', args: [what], target };
1717
+ }
1718
+
1719
+ parseRemove() {
1720
+ this.expect('remove');
1721
+ if (this.matchType('selector')) {
1722
+ const what = this.parseExpression();
1723
+ let target;
1724
+ if (this.match('from')) {
1725
+ this.advance();
1726
+ target = this.parseExpression();
1727
+ }
1728
+ return { type: 'command', name: 'removeClass', args: [what], target };
1729
+ }
1730
+ const target = this.parseExpression();
1731
+ return { type: 'command', name: 'remove', args: [], target };
1732
+ }
1733
+
1734
+ parsePut() {
1735
+ this.expect('put');
1736
+ const content = this.parseExpression();
1737
+ let modifier = 'into';
1738
+ if (this.match('into', 'before', 'after', 'at')) {
1739
+ modifier = this.advance().value;
1740
+ if (modifier === 'at') {
1741
+ const pos = this.advance().value;
1742
+ this.expect('of');
1743
+ modifier = 'at ' + pos + ' of';
1744
+ }
1745
+ }
1746
+ const target = this.parseExpression();
1747
+ return { type: 'command', name: 'put', args: [content], target, modifier };
1748
+ }
1749
+
1750
+ parseAppend() {
1751
+ this.expect('append');
1752
+ const content = this.parseExpression();
1753
+ let target;
1754
+ if (this.match('to')) {
1755
+ this.advance();
1756
+ target = this.parseExpression();
1757
+ }
1758
+ return { type: 'command', name: 'append', args: [content], target };
1759
+ }
1760
+
1761
+ parseSet() {
1762
+ this.expect('set');
1763
+ const target = this.parseExpression();
1764
+ if (this.match('to')) {
1765
+ this.advance();
1766
+ const value = this.parseExpression();
1767
+ return { type: 'command', name: 'set', args: [target, value] };
1768
+ }
1769
+ return { type: 'command', name: 'set', args: [target] };
1770
+ }
1771
+
1772
+ parseGet() {
1773
+ this.expect('get');
1774
+ return { type: 'command', name: 'get', args: [this.parseExpression()] };
1775
+ }
1776
+
1777
+ parseCall() {
1778
+ this.expect('call');
1779
+ return { type: 'command', name: 'call', args: [this.parseExpression()] };
1780
+ }
1781
+
1782
+ parseLog() {
1783
+ this.expect('log');
1784
+ const args = [];
1785
+ while (!this.isAtEnd() && !this.match('then', 'and', 'end', 'else')) {
1786
+ args.push(this.parseExpression());
1787
+ if (this.match(',')) this.advance();
1788
+ else break;
1789
+ }
1790
+ return { type: 'command', name: 'log', args };
1791
+ }
1792
+
1793
+ parseSend() {
1794
+ this.advance();
1795
+ const event = this.advance().value;
1796
+ let target;
1797
+ if (this.match('to')) {
1798
+ this.advance();
1799
+ target = this.parseExpression();
1800
+ }
1801
+ return { type: 'command', name: 'send', args: [{ type: 'literal', value: event }], target };
1802
+ }
1803
+
1804
+ parseWait() {
1805
+ this.expect('wait');
1806
+ if (this.match('for')) {
1807
+ this.advance();
1808
+ const event = this.advance().value;
1809
+ let target;
1810
+ if (this.match('from')) {
1811
+ this.advance();
1812
+ target = this.parseExpression();
1813
+ }
1814
+ return { type: 'command', name: 'waitFor', args: [{ type: 'literal', value: event }], target };
1815
+ }
1816
+ return { type: 'command', name: 'wait', args: [this.parseExpression()] };
1817
+ }
1818
+
1819
+ parseShow() {
1820
+ this.expect('show');
1821
+ let target;
1822
+ const modifiers = {};
1823
+ if (!this.isAtEnd() && !this.match('then', 'and', 'end', 'else', 'when', 'where')) {
1824
+ target = this.parseExpression();
1825
+ }
1826
+ if (!this.isAtEnd() && this.match('when', 'where')) {
1827
+ const keyword = this.advance().value;
1828
+ modifiers[keyword] = this.parseExpression();
1829
+ }
1830
+ return { type: 'command', name: 'show', args: [], target, modifiers };
1831
+ }
1832
+
1833
+ parseHide() {
1834
+ this.expect('hide');
1835
+ let target;
1836
+ const modifiers = {};
1837
+ if (!this.isAtEnd() && !this.match('then', 'and', 'end', 'else', 'when', 'where')) {
1838
+ target = this.parseExpression();
1839
+ }
1840
+ if (!this.isAtEnd() && this.match('when', 'where')) {
1841
+ const keyword = this.advance().value;
1842
+ modifiers[keyword] = this.parseExpression();
1843
+ }
1844
+ return { type: 'command', name: 'hide', args: [], target, modifiers };
1845
+ }
1846
+
1847
+ parseTake() {
1848
+ this.expect('take');
1849
+ const what = this.parseExpression();
1850
+ let from;
1851
+ if (this.match('from')) {
1852
+ this.advance();
1853
+ from = this.parseExpression();
1854
+ }
1855
+ return { type: 'command', name: 'take', args: [what], target: from };
1856
+ }
1857
+
1858
+ parseIncDec(name) {
1859
+ this.advance();
1860
+ const target = this.parseExpression();
1861
+ let amount = { type: 'literal', value: 1 };
1862
+ if (this.match('by')) {
1863
+ this.advance();
1864
+ amount = this.parseExpression();
1865
+ }
1866
+ return { type: 'command', name, args: [target, amount] };
1867
+ }
1868
+
1869
+ parseFocusBlur(name) {
1870
+ this.advance();
1871
+ let target;
1872
+ if (!this.isAtEnd() && !this.match('then', 'and', 'end', 'else')) {
1873
+ target = this.parseExpression();
1874
+ }
1875
+ return { type: 'command', name, args: [], target };
1876
+ }
1877
+
1878
+ parseGo() {
1879
+ this.expect('go');
1880
+ if (this.match('to')) this.advance();
1881
+ if (this.match('url')) this.advance();
1882
+ const dest = this.parseExpression();
1883
+ return { type: 'command', name: 'go', args: [dest] };
1884
+ }
1885
+
1886
+ parseReturn() {
1887
+ this.expect('return');
1888
+ let value;
1889
+ if (!this.isAtEnd() && !this.match('then', 'and', 'end', 'else')) {
1890
+ value = this.parseExpression();
1891
+ }
1892
+ return { type: 'command', name: 'return', args: value ? [value] : [] };
1893
+ }
1894
+
1895
+ parseTransition() {
1896
+ this.expect('transition');
1897
+ let target;
1898
+ if (this.match('my', 'its')) {
1899
+ const ref = this.advance().value;
1900
+ target = { type: 'identifier', value: ref === 'my' ? 'me' : 'it' };
1901
+ } else if (this.matchType('selector')) {
1902
+ const expr = this.parseExpression();
1903
+ if (expr.type === 'possessive') {
1904
+ return this.parseTransitionRest(expr.object, expr.property);
1905
+ }
1906
+ target = expr;
1907
+ }
1908
+
1909
+ const propToken = this.peek();
1910
+ let property;
1911
+ if (propToken.type === 'styleProperty') {
1912
+ property = this.advance().value;
1913
+ } else if (propToken.type === 'identifier' || propToken.type === 'keyword') {
1914
+ property = this.advance().value;
1915
+ } else {
1916
+ property = 'opacity';
1917
+ }
1918
+
1919
+ return this.parseTransitionRest(target, property);
1920
+ }
1921
+
1922
+ parseTransitionRest(target, property) {
1923
+ let toValue = { type: 'literal', value: 1 };
1924
+ if (this.match('to')) {
1925
+ this.advance();
1926
+ toValue = this.parseExpression();
1927
+ }
1928
+ let duration = { type: 'literal', value: 300 };
1929
+ if (this.match('over')) {
1930
+ this.advance();
1931
+ duration = this.parseExpression();
1932
+ }
1933
+ return { type: 'command', name: 'transition', args: [{ type: 'literal', value: property }, toValue, duration], target };
1934
+ }
1935
+
1936
+ parseExpression() { return this.parseOr(); }
1937
+
1938
+ parseOr() {
1939
+ let left = this.parseAnd();
1940
+ while (this.match('or', '||')) {
1941
+ this.advance();
1942
+ left = { type: 'binary', operator: 'or', left, right: this.parseAnd() };
1943
+ }
1944
+ return left;
1945
+ }
1946
+
1947
+ parseAnd() {
1948
+ let left = this.parseEquality();
1949
+ while (this.match('and', '&&') && !this.isCommandKeyword(this.peek(1))) {
1950
+ this.advance();
1951
+ left = { type: 'binary', operator: 'and', left, right: this.parseEquality() };
1952
+ }
1953
+ return left;
1954
+ }
1955
+
1956
+ isCommandKeyword(token) {
1957
+ const cmds = ['toggle', 'add', 'remove', 'set', 'put', 'log', 'send', 'wait', 'show', 'hide', 'increment', 'decrement', 'focus', 'blur', 'go'];
1958
+ return cmds.includes(normalizeCommand(token.value));
1959
+ }
1960
+
1961
+ parseEquality() {
1962
+ let left = this.parseComparison();
1963
+ while (this.match('==', '!=', 'is', 'matches', 'contains', 'includes', 'has')) {
1964
+ const op = this.advance().value;
1965
+ if (op.toLowerCase() === 'is' && this.match('not')) {
1966
+ this.advance();
1967
+ left = { type: 'binary', operator: 'is not', left, right: this.parseComparison() };
1968
+ } else {
1969
+ left = { type: 'binary', operator: op, left, right: this.parseComparison() };
1970
+ }
1971
+ }
1972
+ return left;
1973
+ }
1974
+
1975
+ parseComparison() {
1976
+ let left = this.parseAdditive();
1977
+ while (this.match('<', '>', '<=', '>=')) {
1978
+ const op = this.advance().value;
1979
+ left = { type: 'binary', operator: op, left, right: this.parseAdditive() };
1980
+ }
1981
+ return left;
1982
+ }
1983
+
1984
+ parseAdditive() {
1985
+ let left = this.parseMultiplicative();
1986
+ while (this.match('+', '-')) {
1987
+ const op = this.advance().value;
1988
+ left = { type: 'binary', operator: op, left, right: this.parseMultiplicative() };
1989
+ }
1990
+ return left;
1991
+ }
1992
+
1993
+ parseMultiplicative() {
1994
+ let left = this.parseUnary();
1995
+ while (this.match('*', '/', '%')) {
1996
+ const op = this.advance().value;
1997
+ left = { type: 'binary', operator: op, left, right: this.parseUnary() };
1998
+ }
1999
+ return left;
2000
+ }
2001
+
2002
+ parseUnary() {
2003
+ if (this.match('not', '!')) {
2004
+ this.advance();
2005
+ return { type: 'unary', operator: 'not', operand: this.parseUnary() };
2006
+ }
2007
+ if (this.match('-') && this.peek(1).type === 'number') {
2008
+ this.advance();
2009
+ const num = this.advance();
2010
+ return { type: 'literal', value: -parseFloat(num.value) };
2011
+ }
2012
+ return this.parsePostfix();
2013
+ }
2014
+
2015
+ parsePostfix() {
2016
+ let left = this.parsePrimary();
2017
+ while (true) {
2018
+ if (this.match("'s")) {
2019
+ this.advance();
2020
+ const next = this.peek();
2021
+ const prop = next.type === 'styleProperty' ? this.advance().value : this.advance().value;
2022
+ left = { type: 'possessive', object: left, property: prop };
2023
+ } else if (this.peek().type === 'styleProperty') {
2024
+ const prop = this.advance().value;
2025
+ left = { type: 'possessive', object: left, property: prop };
2026
+ } else if (this.peek().value === '.') {
2027
+ this.advance();
2028
+ const prop = this.advance().value;
2029
+ left = { type: 'member', object: left, property: prop };
2030
+ } else if (this.peek().type === 'selector' && this.peek().value.startsWith('.')) {
2031
+ const prop = this.advance().value.slice(1);
2032
+ left = { type: 'member', object: left, property: prop };
2033
+ } else if (this.peek().value === '(') {
2034
+ this.advance();
2035
+ const args = [];
2036
+ while (!this.match(')')) {
2037
+ args.push(this.parseExpression());
2038
+ if (this.match(',')) this.advance();
2039
+ }
2040
+ this.expect(')');
2041
+ left = { type: 'call', callee: left, args };
2042
+ } else if (this.peek().value === '[' && left.type !== 'selector') {
2043
+ this.advance();
2044
+ const index = this.parseExpression();
2045
+ this.expect(']');
2046
+ left = { type: 'member', object: left, property: index, computed: true };
2047
+ } else {
2048
+ break;
2049
+ }
2050
+ }
2051
+ return left;
2052
+ }
2053
+
2054
+ parsePrimary() {
2055
+ const token = this.peek();
2056
+
2057
+ if (token.value === '(') {
2058
+ this.advance();
2059
+ const expr = this.parseExpression();
2060
+ this.expect(')');
2061
+ return expr;
2062
+ }
2063
+
2064
+ if (token.value === '{') return this.parseObjectLiteral();
2065
+ if (token.value === '[') return this.parseArrayLiteral();
2066
+
2067
+ if (token.type === 'number') {
2068
+ this.advance();
2069
+ const val = token.value;
2070
+ if (val.endsWith('ms')) return { type: 'literal', value: parseInt(val), unit: 'ms' };
2071
+ if (val.endsWith('s')) return { type: 'literal', value: parseFloat(val) * 1000, unit: 'ms' };
2072
+ return { type: 'literal', value: parseFloat(val) };
2073
+ }
2074
+
2075
+ if (token.type === 'string') {
2076
+ this.advance();
2077
+ return { type: 'literal', value: token.value.slice(1, -1) };
2078
+ }
2079
+
2080
+ if (this.match('true')) { this.advance(); return { type: 'literal', value: true }; }
2081
+ if (this.match('false')) { this.advance(); return { type: 'literal', value: false }; }
2082
+ if (this.match('null')) { this.advance(); return { type: 'literal', value: null }; }
2083
+ if (this.match('undefined')) { this.advance(); return { type: 'literal', value: undefined }; }
2084
+
2085
+ if (token.type === 'localVar') {
2086
+ this.advance();
2087
+ return { type: 'variable', name: token.value, scope: 'local' };
2088
+ }
2089
+ if (token.type === 'globalVar') {
2090
+ this.advance();
2091
+ return { type: 'variable', name: token.value, scope: 'global' };
2092
+ }
2093
+ if (token.type === 'selector') {
2094
+ this.advance();
2095
+ return { type: 'selector', value: token.value };
2096
+ }
2097
+
2098
+ if (this.match('my')) {
2099
+ this.advance();
2100
+ const next = this.peek();
2101
+ if ((next.type === 'identifier' || next.type === 'keyword') && !this.isCommandKeyword(next)) {
2102
+ const prop = this.advance().value;
2103
+ return { type: 'possessive', object: { type: 'identifier', value: 'me' }, property: prop };
2104
+ }
2105
+ return { type: 'identifier', value: 'me' };
2106
+ }
2107
+ if (this.match('its')) {
2108
+ this.advance();
2109
+ const next = this.peek();
2110
+ if ((next.type === 'identifier' || next.type === 'keyword') && !this.isCommandKeyword(next)) {
2111
+ const prop = this.advance().value;
2112
+ return { type: 'possessive', object: { type: 'identifier', value: 'it' }, property: prop };
2113
+ }
2114
+ return { type: 'identifier', value: 'it' };
2115
+ }
2116
+ if (this.match('me')) { this.advance(); return { type: 'identifier', value: 'me' }; }
2117
+ if (this.match('it')) { this.advance(); return { type: 'identifier', value: 'it' }; }
2118
+ if (this.match('you')) { this.advance(); return { type: 'identifier', value: 'you' }; }
2119
+
2120
+ if (this.match('the', 'a', 'an')) {
2121
+ this.advance();
2122
+ if (this.match('first', 'last', 'next', 'previous', 'closest', 'parent')) {
2123
+ const position = this.advance().value;
2124
+ const target = this.parsePositionalTarget();
2125
+ return { type: 'positional', position, target };
2126
+ }
2127
+ return this.parsePrimary();
2128
+ }
2129
+
2130
+ if (this.match('first', 'last', 'next', 'previous', 'closest', 'parent')) {
2131
+ const position = this.advance().value;
2132
+ const target = this.parsePositionalTarget();
2133
+ return { type: 'positional', position, target };
2134
+ }
2135
+
2136
+ if (token.type === 'identifier' || token.type === 'keyword') {
2137
+ this.advance();
2138
+ return { type: 'identifier', value: token.value };
2139
+ }
2140
+
2141
+ this.advance();
2142
+ return { type: 'identifier', value: token.value };
2143
+ }
2144
+
2145
+ parseObjectLiteral() {
2146
+ this.expect('{');
2147
+ const properties = [];
2148
+ while (!this.match('}')) {
2149
+ const key = this.advance().value;
2150
+ this.expect(':');
2151
+ const value = this.parseExpression();
2152
+ properties.push({ key, value });
2153
+ if (this.match(',')) this.advance();
2154
+ }
2155
+ this.expect('}');
2156
+ return { type: 'object', properties };
2157
+ }
2158
+
2159
+ parseArrayLiteral() {
2160
+ this.expect('[');
2161
+ const elements = [];
2162
+ while (!this.match(']')) {
2163
+ elements.push(this.parseExpression());
2164
+ if (this.match(',')) this.advance();
2165
+ }
2166
+ this.expect(']');
2167
+ return { type: 'array', elements };
2168
+ }
2169
+
2170
+ parsePositionalTarget() {
2171
+ const token = this.peek();
2172
+ if (token.type === 'selector') {
2173
+ return { type: 'selector', value: this.advance().value };
2174
+ }
2175
+ if (token.type === 'identifier' || token.type === 'keyword') {
2176
+ return { type: 'identifier', value: this.advance().value };
2177
+ }
2178
+ return this.parseExpression();
2179
+ }
2180
+ }
2181
+ `;
2182
+ function getParserTemplate(type) {
2183
+ return type === 'lite' ? LITE_PARSER_TEMPLATE : HYBRID_PARSER_TEMPLATE;
2184
+ }
2185
+ const LITE_PARSER_COMMANDS = [
2186
+ 'toggle',
2187
+ 'add',
2188
+ 'remove',
2189
+ 'put',
2190
+ 'set',
2191
+ 'log',
2192
+ 'send',
2193
+ 'wait',
2194
+ 'show',
2195
+ 'hide',
2196
+ ];
2197
+ function canUseLiteParser(commands, blocks, positional) {
2198
+ if (blocks.length > 0)
2199
+ return false;
2200
+ if (positional)
2201
+ return false;
2202
+ const liteCommands = new Set(LITE_PARSER_COMMANDS);
2203
+ return commands.every(cmd => liteCommands.has(cmd));
2204
+ }
2205
+
2206
+ const AVAILABLE_COMMANDS = [
2207
+ 'toggle',
2208
+ 'add',
2209
+ 'remove',
2210
+ 'removeClass',
2211
+ 'show',
2212
+ 'hide',
2213
+ 'put',
2214
+ 'append',
2215
+ 'take',
2216
+ 'set',
2217
+ 'get',
2218
+ 'increment',
2219
+ 'decrement',
2220
+ 'wait',
2221
+ 'transition',
2222
+ 'send',
2223
+ 'trigger',
2224
+ 'log',
2225
+ 'call',
2226
+ 'copy',
2227
+ 'beep',
2228
+ 'go',
2229
+ 'push',
2230
+ 'push-url',
2231
+ 'replace',
2232
+ 'replace-url',
2233
+ 'focus',
2234
+ 'blur',
2235
+ 'return',
2236
+ 'break',
2237
+ 'continue',
2238
+ 'halt',
2239
+ 'exit',
2240
+ 'throw',
2241
+ 'js',
2242
+ 'morph',
2243
+ ];
2244
+ const AVAILABLE_BLOCKS = ['if', 'repeat', 'for', 'while', 'fetch'];
2245
+ const FULL_RUNTIME_ONLY_COMMANDS = [
2246
+ 'async',
2247
+ 'make',
2248
+ 'swap',
2249
+ 'process-partials',
2250
+ 'bind',
2251
+ 'persist',
2252
+ 'default',
2253
+ 'tell',
2254
+ 'pick',
2255
+ 'unless',
2256
+ 'settle',
2257
+ 'measure',
2258
+ 'install',
2259
+ ];
2260
+ function isAvailableCommand(command) {
2261
+ return AVAILABLE_COMMANDS.includes(command);
2262
+ }
2263
+ function isAvailableBlock(block) {
2264
+ return AVAILABLE_BLOCKS.includes(block);
2265
+ }
2266
+ function requiresFullRuntime(command) {
2267
+ return FULL_RUNTIME_ONLY_COMMANDS.includes(command);
2268
+ }
2269
+
2270
+ export { AVAILABLE_BLOCKS, AVAILABLE_COMMANDS, BLOCK_IMPLEMENTATIONS, COMMAND_IMPLEMENTATIONS, ELEMENT_ARRAY_COMMANDS, FULL_RUNTIME_ONLY_COMMANDS, HYBRID_PARSER_TEMPLATE, LITE_PARSER_COMMANDS, LITE_PARSER_TEMPLATE, MORPH_COMMANDS, STYLE_COMMANDS, canUseLiteParser, generateBundle, generateBundleCode, getAvailableBlocks, getAvailableCommands, getBlockImplementations, getCommandImplementations, getParserTemplate, isAvailableBlock, isAvailableCommand, requiresFullRuntime };
2271
+ //# sourceMappingURL=index.mjs.map