@lokascript/semantic 1.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.
- package/LICENSE +21 -0
- package/README.md +686 -0
- package/dist/browser-ar.ar.global.js +2 -0
- package/dist/browser-core.core.global.js +2 -0
- package/dist/browser-de.de.global.js +2 -0
- package/dist/browser-east-asian.east-asian.global.js +2 -0
- package/dist/browser-en-tr.en-tr.global.js +2 -0
- package/dist/browser-en.en.global.js +2 -0
- package/dist/browser-es-en.es-en.global.js +2 -0
- package/dist/browser-es.es.global.js +2 -0
- package/dist/browser-fr.fr.global.js +2 -0
- package/dist/browser-id.id.global.js +2 -0
- package/dist/browser-ja.ja.global.js +2 -0
- package/dist/browser-ko.ko.global.js +2 -0
- package/dist/browser-lazy.lazy.global.js +2 -0
- package/dist/browser-priority.priority.global.js +2 -0
- package/dist/browser-pt.pt.global.js +2 -0
- package/dist/browser-qu.qu.global.js +2 -0
- package/dist/browser-sw.sw.global.js +2 -0
- package/dist/browser-tr.tr.global.js +2 -0
- package/dist/browser-western.western.global.js +2 -0
- package/dist/browser-zh.zh.global.js +2 -0
- package/dist/browser.global.js +3 -0
- package/dist/browser.global.js.map +1 -0
- package/dist/index.cjs +35051 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3426 -0
- package/dist/index.d.ts +3426 -0
- package/dist/index.js +34890 -0
- package/dist/index.js.map +1 -0
- package/dist/languages/ar.d.ts +78 -0
- package/dist/languages/ar.js +1622 -0
- package/dist/languages/ar.js.map +1 -0
- package/dist/languages/de.d.ts +38 -0
- package/dist/languages/de.js +1168 -0
- package/dist/languages/de.js.map +1 -0
- package/dist/languages/en.d.ts +44 -0
- package/dist/languages/en.js +3491 -0
- package/dist/languages/en.js.map +1 -0
- package/dist/languages/es.d.ts +52 -0
- package/dist/languages/es.js +1493 -0
- package/dist/languages/es.js.map +1 -0
- package/dist/languages/fr.d.ts +37 -0
- package/dist/languages/fr.js +1159 -0
- package/dist/languages/fr.js.map +1 -0
- package/dist/languages/id.d.ts +35 -0
- package/dist/languages/id.js +1152 -0
- package/dist/languages/id.js.map +1 -0
- package/dist/languages/ja.d.ts +53 -0
- package/dist/languages/ja.js +1430 -0
- package/dist/languages/ja.js.map +1 -0
- package/dist/languages/ko.d.ts +51 -0
- package/dist/languages/ko.js +1729 -0
- package/dist/languages/ko.js.map +1 -0
- package/dist/languages/pt.d.ts +37 -0
- package/dist/languages/pt.js +1127 -0
- package/dist/languages/pt.js.map +1 -0
- package/dist/languages/qu.d.ts +36 -0
- package/dist/languages/qu.js +1143 -0
- package/dist/languages/qu.js.map +1 -0
- package/dist/languages/sw.d.ts +35 -0
- package/dist/languages/sw.js +1147 -0
- package/dist/languages/sw.js.map +1 -0
- package/dist/languages/tr.d.ts +45 -0
- package/dist/languages/tr.js +1529 -0
- package/dist/languages/tr.js.map +1 -0
- package/dist/languages/zh.d.ts +58 -0
- package/dist/languages/zh.js +1257 -0
- package/dist/languages/zh.js.map +1 -0
- package/dist/types-C4dcj53L.d.ts +600 -0
- package/package.json +202 -0
- package/src/__test-utils__/index.ts +7 -0
- package/src/__test-utils__/test-helpers.ts +8 -0
- package/src/__types__/test-helpers.ts +122 -0
- package/src/analysis/index.ts +479 -0
- package/src/ast-builder/command-mappers.ts +1133 -0
- package/src/ast-builder/expression-parser/index.ts +41 -0
- package/src/ast-builder/expression-parser/parser.ts +563 -0
- package/src/ast-builder/expression-parser/tokenizer.ts +394 -0
- package/src/ast-builder/expression-parser/types.ts +208 -0
- package/src/ast-builder/index.ts +536 -0
- package/src/ast-builder/value-converters.ts +172 -0
- package/src/bridge.ts +275 -0
- package/src/browser-ar.ts +162 -0
- package/src/browser-core.ts +231 -0
- package/src/browser-de.ts +162 -0
- package/src/browser-east-asian.ts +173 -0
- package/src/browser-en-tr.ts +165 -0
- package/src/browser-en.ts +157 -0
- package/src/browser-es-en.ts +200 -0
- package/src/browser-es.ts +170 -0
- package/src/browser-fr.ts +162 -0
- package/src/browser-id.ts +162 -0
- package/src/browser-ja.ts +162 -0
- package/src/browser-ko.ts +162 -0
- package/src/browser-lazy.ts +189 -0
- package/src/browser-priority.ts +214 -0
- package/src/browser-pt.ts +162 -0
- package/src/browser-qu.ts +162 -0
- package/src/browser-sw.ts +162 -0
- package/src/browser-tr.ts +162 -0
- package/src/browser-western.ts +181 -0
- package/src/browser-zh.ts +162 -0
- package/src/browser.ts +268 -0
- package/src/cache/index.ts +14 -0
- package/src/cache/semantic-cache.ts +344 -0
- package/src/core-bridge.ts +372 -0
- package/src/explicit/converter.ts +258 -0
- package/src/explicit/index.ts +18 -0
- package/src/explicit/parser.ts +236 -0
- package/src/explicit/renderer.ts +424 -0
- package/src/generators/command-schemas.ts +1636 -0
- package/src/generators/event-handler-generator.ts +109 -0
- package/src/generators/index.ts +117 -0
- package/src/generators/language-profiles.ts +139 -0
- package/src/generators/pattern-generator.ts +537 -0
- package/src/generators/profiles/arabic.ts +131 -0
- package/src/generators/profiles/bengali.ts +132 -0
- package/src/generators/profiles/chinese.ts +124 -0
- package/src/generators/profiles/english.ts +113 -0
- package/src/generators/profiles/french.ts +125 -0
- package/src/generators/profiles/german.ts +126 -0
- package/src/generators/profiles/hindi.ts +146 -0
- package/src/generators/profiles/index.ts +46 -0
- package/src/generators/profiles/indonesian.ts +125 -0
- package/src/generators/profiles/italian.ts +139 -0
- package/src/generators/profiles/japanese.ts +149 -0
- package/src/generators/profiles/korean.ts +127 -0
- package/src/generators/profiles/marker-templates.ts +288 -0
- package/src/generators/profiles/ms.ts +130 -0
- package/src/generators/profiles/polish.ts +249 -0
- package/src/generators/profiles/portuguese.ts +115 -0
- package/src/generators/profiles/quechua.ts +113 -0
- package/src/generators/profiles/russian.ts +260 -0
- package/src/generators/profiles/spanish.ts +130 -0
- package/src/generators/profiles/swahili.ts +129 -0
- package/src/generators/profiles/thai.ts +132 -0
- package/src/generators/profiles/tl.ts +128 -0
- package/src/generators/profiles/turkish.ts +124 -0
- package/src/generators/profiles/types.ts +165 -0
- package/src/generators/profiles/ukrainian.ts +270 -0
- package/src/generators/profiles/vietnamese.ts +133 -0
- package/src/generators/schema-error-codes.ts +160 -0
- package/src/generators/schema-validator.ts +391 -0
- package/src/index.ts +429 -0
- package/src/language-building-schema.ts +3170 -0
- package/src/language-loader.ts +394 -0
- package/src/languages/_all.ts +65 -0
- package/src/languages/ar.ts +15 -0
- package/src/languages/bn.ts +16 -0
- package/src/languages/de.ts +15 -0
- package/src/languages/en.ts +29 -0
- package/src/languages/es.ts +15 -0
- package/src/languages/fr.ts +15 -0
- package/src/languages/hi.ts +26 -0
- package/src/languages/id.ts +15 -0
- package/src/languages/index.ts +18 -0
- package/src/languages/it.ts +15 -0
- package/src/languages/ja.ts +15 -0
- package/src/languages/ko.ts +15 -0
- package/src/languages/ms.ts +16 -0
- package/src/languages/pl.ts +18 -0
- package/src/languages/pt.ts +15 -0
- package/src/languages/qu.ts +15 -0
- package/src/languages/ru.ts +26 -0
- package/src/languages/sw.ts +15 -0
- package/src/languages/th.ts +16 -0
- package/src/languages/tl.ts +16 -0
- package/src/languages/tr.ts +15 -0
- package/src/languages/uk.ts +26 -0
- package/src/languages/vi.ts +16 -0
- package/src/languages/zh.ts +15 -0
- package/src/parser/index.ts +15 -0
- package/src/parser/pattern-matcher.ts +1181 -0
- package/src/parser/semantic-parser.ts +573 -0
- package/src/parser/utils/index.ts +35 -0
- package/src/parser/utils/marker-resolution.ts +111 -0
- package/src/parser/utils/possessive-keywords.ts +43 -0
- package/src/parser/utils/role-positioning.ts +70 -0
- package/src/parser/utils/type-validation.ts +134 -0
- package/src/patterns/add/ar.ts +71 -0
- package/src/patterns/add/bn.ts +70 -0
- package/src/patterns/add/hi.ts +69 -0
- package/src/patterns/add/index.ts +87 -0
- package/src/patterns/add/it.ts +61 -0
- package/src/patterns/add/ja.ts +93 -0
- package/src/patterns/add/ko.ts +74 -0
- package/src/patterns/add/ms.ts +30 -0
- package/src/patterns/add/pl.ts +62 -0
- package/src/patterns/add/ru.ts +62 -0
- package/src/patterns/add/th.ts +49 -0
- package/src/patterns/add/tl.ts +30 -0
- package/src/patterns/add/tr.ts +71 -0
- package/src/patterns/add/uk.ts +62 -0
- package/src/patterns/add/vi.ts +61 -0
- package/src/patterns/add/zh.ts +71 -0
- package/src/patterns/builders.ts +207 -0
- package/src/patterns/decrement/bn.ts +70 -0
- package/src/patterns/decrement/de.ts +42 -0
- package/src/patterns/decrement/hi.ts +68 -0
- package/src/patterns/decrement/index.ts +79 -0
- package/src/patterns/decrement/it.ts +69 -0
- package/src/patterns/decrement/ms.ts +30 -0
- package/src/patterns/decrement/pl.ts +58 -0
- package/src/patterns/decrement/ru.ts +58 -0
- package/src/patterns/decrement/th.ts +49 -0
- package/src/patterns/decrement/tl.ts +30 -0
- package/src/patterns/decrement/tr.ts +48 -0
- package/src/patterns/decrement/uk.ts +58 -0
- package/src/patterns/decrement/vi.ts +61 -0
- package/src/patterns/decrement/zh.ts +32 -0
- package/src/patterns/en.ts +302 -0
- package/src/patterns/event-handler/ar.ts +151 -0
- package/src/patterns/event-handler/bn.ts +72 -0
- package/src/patterns/event-handler/de.ts +117 -0
- package/src/patterns/event-handler/en.ts +117 -0
- package/src/patterns/event-handler/es.ts +136 -0
- package/src/patterns/event-handler/fr.ts +117 -0
- package/src/patterns/event-handler/hi.ts +64 -0
- package/src/patterns/event-handler/id.ts +117 -0
- package/src/patterns/event-handler/index.ts +119 -0
- package/src/patterns/event-handler/it.ts +54 -0
- package/src/patterns/event-handler/ja.ts +118 -0
- package/src/patterns/event-handler/ko.ts +133 -0
- package/src/patterns/event-handler/ms.ts +30 -0
- package/src/patterns/event-handler/pl.ts +62 -0
- package/src/patterns/event-handler/pt.ts +117 -0
- package/src/patterns/event-handler/qu.ts +66 -0
- package/src/patterns/event-handler/ru.ts +62 -0
- package/src/patterns/event-handler/shared.ts +270 -0
- package/src/patterns/event-handler/sw.ts +117 -0
- package/src/patterns/event-handler/th.ts +53 -0
- package/src/patterns/event-handler/tl.ts +30 -0
- package/src/patterns/event-handler/tr.ts +170 -0
- package/src/patterns/event-handler/uk.ts +62 -0
- package/src/patterns/event-handler/vi.ts +61 -0
- package/src/patterns/event-handler/zh.ts +150 -0
- package/src/patterns/get/ar.ts +49 -0
- package/src/patterns/get/bn.ts +47 -0
- package/src/patterns/get/de.ts +32 -0
- package/src/patterns/get/hi.ts +52 -0
- package/src/patterns/get/index.ts +83 -0
- package/src/patterns/get/it.ts +56 -0
- package/src/patterns/get/ja.ts +53 -0
- package/src/patterns/get/ko.ts +53 -0
- package/src/patterns/get/ms.ts +30 -0
- package/src/patterns/get/pl.ts +57 -0
- package/src/patterns/get/ru.ts +57 -0
- package/src/patterns/get/th.ts +29 -0
- package/src/patterns/get/tl.ts +30 -0
- package/src/patterns/get/uk.ts +57 -0
- package/src/patterns/get/vi.ts +48 -0
- package/src/patterns/grammar-transformed/index.ts +39 -0
- package/src/patterns/grammar-transformed/ja.ts +1713 -0
- package/src/patterns/grammar-transformed/ko.ts +1311 -0
- package/src/patterns/grammar-transformed/tr.ts +1067 -0
- package/src/patterns/hide/ar.ts +67 -0
- package/src/patterns/hide/bn.ts +47 -0
- package/src/patterns/hide/de.ts +36 -0
- package/src/patterns/hide/hi.ts +61 -0
- package/src/patterns/hide/index.ts +91 -0
- package/src/patterns/hide/it.ts +56 -0
- package/src/patterns/hide/ja.ts +69 -0
- package/src/patterns/hide/ko.ts +69 -0
- package/src/patterns/hide/ms.ts +30 -0
- package/src/patterns/hide/pl.ts +57 -0
- package/src/patterns/hide/ru.ts +57 -0
- package/src/patterns/hide/th.ts +29 -0
- package/src/patterns/hide/tl.ts +30 -0
- package/src/patterns/hide/tr.ts +65 -0
- package/src/patterns/hide/uk.ts +57 -0
- package/src/patterns/hide/vi.ts +56 -0
- package/src/patterns/hide/zh.ts +68 -0
- package/src/patterns/increment/bn.ts +70 -0
- package/src/patterns/increment/de.ts +36 -0
- package/src/patterns/increment/hi.ts +68 -0
- package/src/patterns/increment/index.ts +79 -0
- package/src/patterns/increment/it.ts +69 -0
- package/src/patterns/increment/ms.ts +30 -0
- package/src/patterns/increment/pl.ts +58 -0
- package/src/patterns/increment/ru.ts +58 -0
- package/src/patterns/increment/th.ts +49 -0
- package/src/patterns/increment/tl.ts +30 -0
- package/src/patterns/increment/tr.ts +52 -0
- package/src/patterns/increment/uk.ts +58 -0
- package/src/patterns/increment/vi.ts +61 -0
- package/src/patterns/increment/zh.ts +32 -0
- package/src/patterns/index.ts +84 -0
- package/src/patterns/languages/en/control-flow.ts +93 -0
- package/src/patterns/languages/en/fetch.ts +62 -0
- package/src/patterns/languages/en/index.ts +42 -0
- package/src/patterns/languages/en/repeat.ts +67 -0
- package/src/patterns/languages/en/set.ts +48 -0
- package/src/patterns/languages/en/swap.ts +38 -0
- package/src/patterns/languages/en/temporal.ts +57 -0
- package/src/patterns/put/ar.ts +74 -0
- package/src/patterns/put/bn.ts +53 -0
- package/src/patterns/put/en.ts +74 -0
- package/src/patterns/put/es.ts +74 -0
- package/src/patterns/put/hi.ts +69 -0
- package/src/patterns/put/id.ts +96 -0
- package/src/patterns/put/index.ts +99 -0
- package/src/patterns/put/it.ts +56 -0
- package/src/patterns/put/ja.ts +75 -0
- package/src/patterns/put/ko.ts +67 -0
- package/src/patterns/put/ms.ts +30 -0
- package/src/patterns/put/pl.ts +81 -0
- package/src/patterns/put/ru.ts +85 -0
- package/src/patterns/put/th.ts +32 -0
- package/src/patterns/put/tl.ts +30 -0
- package/src/patterns/put/tr.ts +67 -0
- package/src/patterns/put/uk.ts +85 -0
- package/src/patterns/put/vi.ts +72 -0
- package/src/patterns/put/zh.ts +62 -0
- package/src/patterns/registry.ts +163 -0
- package/src/patterns/remove/ar.ts +71 -0
- package/src/patterns/remove/bn.ts +68 -0
- package/src/patterns/remove/hi.ts +69 -0
- package/src/patterns/remove/index.ts +87 -0
- package/src/patterns/remove/it.ts +69 -0
- package/src/patterns/remove/ja.ts +74 -0
- package/src/patterns/remove/ko.ts +78 -0
- package/src/patterns/remove/ms.ts +30 -0
- package/src/patterns/remove/pl.ts +62 -0
- package/src/patterns/remove/ru.ts +62 -0
- package/src/patterns/remove/th.ts +49 -0
- package/src/patterns/remove/tl.ts +30 -0
- package/src/patterns/remove/tr.ts +78 -0
- package/src/patterns/remove/uk.ts +62 -0
- package/src/patterns/remove/vi.ts +61 -0
- package/src/patterns/remove/zh.ts +72 -0
- package/src/patterns/set/ar.ts +84 -0
- package/src/patterns/set/bn.ts +53 -0
- package/src/patterns/set/de.ts +84 -0
- package/src/patterns/set/es.ts +92 -0
- package/src/patterns/set/fr.ts +88 -0
- package/src/patterns/set/hi.ts +56 -0
- package/src/patterns/set/id.ts +84 -0
- package/src/patterns/set/index.ts +107 -0
- package/src/patterns/set/it.ts +56 -0
- package/src/patterns/set/ja.ts +86 -0
- package/src/patterns/set/ko.ts +85 -0
- package/src/patterns/set/ms.ts +30 -0
- package/src/patterns/set/pl.ts +57 -0
- package/src/patterns/set/pt.ts +84 -0
- package/src/patterns/set/ru.ts +57 -0
- package/src/patterns/set/th.ts +31 -0
- package/src/patterns/set/tl.ts +30 -0
- package/src/patterns/set/tr.ts +107 -0
- package/src/patterns/set/uk.ts +57 -0
- package/src/patterns/set/vi.ts +53 -0
- package/src/patterns/set/zh.ts +84 -0
- package/src/patterns/show/ar.ts +67 -0
- package/src/patterns/show/bn.ts +47 -0
- package/src/patterns/show/de.ts +32 -0
- package/src/patterns/show/fr.ts +32 -0
- package/src/patterns/show/hi.ts +61 -0
- package/src/patterns/show/index.ts +95 -0
- package/src/patterns/show/it.ts +56 -0
- package/src/patterns/show/ja.ts +69 -0
- package/src/patterns/show/ko.ts +73 -0
- package/src/patterns/show/ms.ts +30 -0
- package/src/patterns/show/pl.ts +57 -0
- package/src/patterns/show/ru.ts +57 -0
- package/src/patterns/show/th.ts +29 -0
- package/src/patterns/show/tl.ts +30 -0
- package/src/patterns/show/tr.ts +65 -0
- package/src/patterns/show/uk.ts +57 -0
- package/src/patterns/show/vi.ts +56 -0
- package/src/patterns/show/zh.ts +68 -0
- package/src/patterns/take/ar.ts +51 -0
- package/src/patterns/take/index.ts +31 -0
- package/src/patterns/toggle/ar.ts +61 -0
- package/src/patterns/toggle/bn.ts +70 -0
- package/src/patterns/toggle/en.ts +61 -0
- package/src/patterns/toggle/es.ts +61 -0
- package/src/patterns/toggle/hi.ts +80 -0
- package/src/patterns/toggle/index.ts +95 -0
- package/src/patterns/toggle/it.ts +69 -0
- package/src/patterns/toggle/ja.ts +156 -0
- package/src/patterns/toggle/ko.ts +113 -0
- package/src/patterns/toggle/ms.ts +30 -0
- package/src/patterns/toggle/pl.ts +62 -0
- package/src/patterns/toggle/ru.ts +62 -0
- package/src/patterns/toggle/th.ts +50 -0
- package/src/patterns/toggle/tl.ts +30 -0
- package/src/patterns/toggle/tr.ts +88 -0
- package/src/patterns/toggle/uk.ts +62 -0
- package/src/patterns/toggle/vi.ts +61 -0
- package/src/patterns/toggle/zh.ts +99 -0
- package/src/public-api.ts +286 -0
- package/src/registry.ts +441 -0
- package/src/tokenizers/arabic.ts +723 -0
- package/src/tokenizers/base.ts +1300 -0
- package/src/tokenizers/bengali.ts +289 -0
- package/src/tokenizers/chinese.ts +481 -0
- package/src/tokenizers/english.ts +416 -0
- package/src/tokenizers/french.ts +326 -0
- package/src/tokenizers/german.ts +324 -0
- package/src/tokenizers/hindi.ts +319 -0
- package/src/tokenizers/index.ts +127 -0
- package/src/tokenizers/indonesian.ts +306 -0
- package/src/tokenizers/italian.ts +458 -0
- package/src/tokenizers/japanese.ts +447 -0
- package/src/tokenizers/korean.ts +642 -0
- package/src/tokenizers/morphology/arabic-normalizer.ts +242 -0
- package/src/tokenizers/morphology/french-normalizer.ts +268 -0
- package/src/tokenizers/morphology/german-normalizer.ts +256 -0
- package/src/tokenizers/morphology/index.ts +46 -0
- package/src/tokenizers/morphology/italian-normalizer.ts +329 -0
- package/src/tokenizers/morphology/japanese-normalizer.ts +288 -0
- package/src/tokenizers/morphology/korean-normalizer.ts +428 -0
- package/src/tokenizers/morphology/polish-normalizer.ts +264 -0
- package/src/tokenizers/morphology/portuguese-normalizer.ts +310 -0
- package/src/tokenizers/morphology/spanish-normalizer.ts +327 -0
- package/src/tokenizers/morphology/turkish-normalizer.ts +412 -0
- package/src/tokenizers/morphology/types.ts +211 -0
- package/src/tokenizers/ms.ts +198 -0
- package/src/tokenizers/polish.ts +354 -0
- package/src/tokenizers/portuguese.ts +304 -0
- package/src/tokenizers/quechua.ts +339 -0
- package/src/tokenizers/russian.ts +375 -0
- package/src/tokenizers/spanish.ts +403 -0
- package/src/tokenizers/swahili.ts +303 -0
- package/src/tokenizers/thai.ts +236 -0
- package/src/tokenizers/tl.ts +198 -0
- package/src/tokenizers/turkish.ts +411 -0
- package/src/tokenizers/ukrainian.ts +369 -0
- package/src/tokenizers/vietnamese.ts +410 -0
- package/src/types/grammar-types.ts +617 -0
- package/src/types/unified-profile.ts +267 -0
- package/src/types.ts +709 -0
- package/src/utils/confidence-calculator.ts +147 -0
- package/src/validators/command-validator.ts +380 -0
- package/src/validators/index.ts +15 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic to AST Builder
|
|
3
|
+
*
|
|
4
|
+
* Converts SemanticNodes directly to AST nodes, bypassing the English text
|
|
5
|
+
* generation and re-parsing step.
|
|
6
|
+
*
|
|
7
|
+
* Flow:
|
|
8
|
+
* Japanese → Semantic Parser → SemanticNode → AST Builder → AST
|
|
9
|
+
*
|
|
10
|
+
* Instead of:
|
|
11
|
+
* Japanese → Semantic Parser → SemanticNode → English Text → Parser → AST
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type {
|
|
15
|
+
SemanticNode,
|
|
16
|
+
CommandSemanticNode,
|
|
17
|
+
EventHandlerSemanticNode,
|
|
18
|
+
ConditionalSemanticNode,
|
|
19
|
+
CompoundSemanticNode,
|
|
20
|
+
LoopSemanticNode,
|
|
21
|
+
SemanticRole,
|
|
22
|
+
} from '../types';
|
|
23
|
+
|
|
24
|
+
import { convertValue } from './value-converters';
|
|
25
|
+
import { getCommandMapper, type CommandMapperResult } from './command-mappers';
|
|
26
|
+
import type { ExpressionNode } from './expression-parser';
|
|
27
|
+
|
|
28
|
+
// =============================================================================
|
|
29
|
+
// AST Types (compatible with @lokascript/core)
|
|
30
|
+
// =============================================================================
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Base AST node interface
|
|
34
|
+
*/
|
|
35
|
+
export interface ASTNode {
|
|
36
|
+
readonly type: string;
|
|
37
|
+
readonly start?: number;
|
|
38
|
+
readonly end?: number;
|
|
39
|
+
readonly line?: number;
|
|
40
|
+
readonly column?: number;
|
|
41
|
+
[key: string]: unknown;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Command AST node
|
|
46
|
+
*/
|
|
47
|
+
export interface CommandNode extends ASTNode {
|
|
48
|
+
readonly type: 'command';
|
|
49
|
+
readonly name: string;
|
|
50
|
+
readonly args: ExpressionNode[];
|
|
51
|
+
readonly modifiers?: Record<string, ExpressionNode>;
|
|
52
|
+
readonly isBlocking?: boolean;
|
|
53
|
+
readonly implicitTarget?: ExpressionNode;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Event handler AST node (compatible with @lokascript/core)
|
|
58
|
+
*/
|
|
59
|
+
export interface EventHandlerNode extends ASTNode {
|
|
60
|
+
readonly type: 'eventHandler';
|
|
61
|
+
/** Primary event name */
|
|
62
|
+
readonly event: string;
|
|
63
|
+
/** All event names when using "on event1 or event2" syntax */
|
|
64
|
+
readonly events?: string[];
|
|
65
|
+
/** CSS selector for event delegation ("from" keyword) */
|
|
66
|
+
readonly selector?: string;
|
|
67
|
+
/** Target for "from" clause (as string or expression) */
|
|
68
|
+
readonly target?: string;
|
|
69
|
+
/** Optional event condition ("[condition]" syntax) */
|
|
70
|
+
readonly condition?: ASTNode;
|
|
71
|
+
/** Attribute name for mutation events ("of @attribute" syntax) */
|
|
72
|
+
readonly attributeName?: string;
|
|
73
|
+
/** Target element to watch for changes ("in <target>" syntax) */
|
|
74
|
+
readonly watchTarget?: ExpressionNode;
|
|
75
|
+
/** Event parameter names to destructure (e.g., ['clientX', 'clientY']) */
|
|
76
|
+
readonly args?: string[];
|
|
77
|
+
/** Event parameters (alias for args) */
|
|
78
|
+
readonly params?: string[];
|
|
79
|
+
/** Handler commands */
|
|
80
|
+
readonly commands: ASTNode[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Conditional AST node (if/else)
|
|
85
|
+
*
|
|
86
|
+
* Note: For runtime compatibility, buildConditional() now produces a CommandNode
|
|
87
|
+
* with condition and branches as args, matching what IfCommand expects.
|
|
88
|
+
* This interface is retained for reference but not used as output.
|
|
89
|
+
*/
|
|
90
|
+
export interface ConditionalNode extends ASTNode {
|
|
91
|
+
readonly type: 'if';
|
|
92
|
+
readonly condition: ExpressionNode;
|
|
93
|
+
readonly thenBranch: ASTNode[];
|
|
94
|
+
readonly elseBranch?: ASTNode[];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Command sequence node (runtime-compatible format for chained commands)
|
|
99
|
+
*/
|
|
100
|
+
export interface CommandSequenceNode extends ASTNode {
|
|
101
|
+
readonly type: 'CommandSequence';
|
|
102
|
+
/** Commands in the sequence */
|
|
103
|
+
readonly commands: ASTNode[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Block node (for grouping commands)
|
|
108
|
+
*/
|
|
109
|
+
export interface BlockNode extends ASTNode {
|
|
110
|
+
readonly type: 'block';
|
|
111
|
+
readonly commands: ASTNode[];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// =============================================================================
|
|
115
|
+
// AST Builder
|
|
116
|
+
// =============================================================================
|
|
117
|
+
|
|
118
|
+
export interface ASTBuilderOptions {
|
|
119
|
+
/**
|
|
120
|
+
* Fallback function to parse complex expressions that can't be handled
|
|
121
|
+
* directly by the AST builder. Uses the expression-parser by default.
|
|
122
|
+
*/
|
|
123
|
+
parseExpression?: (input: string) => ExpressionNode | null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Builds AST nodes directly from SemanticNodes.
|
|
128
|
+
*/
|
|
129
|
+
export class ASTBuilder {
|
|
130
|
+
/**
|
|
131
|
+
* Warnings collected during AST building (e.g., type inference issues).
|
|
132
|
+
*/
|
|
133
|
+
public warnings: string[] = [];
|
|
134
|
+
|
|
135
|
+
constructor(_options: ASTBuilderOptions = {}) {
|
|
136
|
+
// Options reserved for future use (e.g., custom expression parser)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Build an AST from a SemanticNode.
|
|
141
|
+
*
|
|
142
|
+
* @param node - The semantic node to convert
|
|
143
|
+
* @returns The corresponding AST node
|
|
144
|
+
*/
|
|
145
|
+
build(node: SemanticNode): ASTNode {
|
|
146
|
+
switch (node.kind) {
|
|
147
|
+
case 'command':
|
|
148
|
+
return this.buildCommand(node as CommandSemanticNode);
|
|
149
|
+
case 'event-handler':
|
|
150
|
+
return this.buildEventHandler(node as EventHandlerSemanticNode);
|
|
151
|
+
case 'conditional':
|
|
152
|
+
return this.buildConditional(node as ConditionalSemanticNode);
|
|
153
|
+
case 'compound':
|
|
154
|
+
return this.buildCompound(node as CompoundSemanticNode);
|
|
155
|
+
case 'loop':
|
|
156
|
+
return this.buildLoop(node as LoopSemanticNode);
|
|
157
|
+
default:
|
|
158
|
+
throw new Error(`Unknown semantic node kind: ${(node as SemanticNode).kind}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Build a CommandNode from a CommandSemanticNode.
|
|
164
|
+
*/
|
|
165
|
+
private buildCommand(node: CommandSemanticNode): CommandNode {
|
|
166
|
+
const mapper = getCommandMapper(node.action);
|
|
167
|
+
|
|
168
|
+
if (mapper) {
|
|
169
|
+
// Use command-specific mapper
|
|
170
|
+
const result = mapper.toAST(node, this);
|
|
171
|
+
|
|
172
|
+
// Handle both new CommandMapperResult format and legacy CommandNode format
|
|
173
|
+
if ('ast' in result && 'warnings' in result) {
|
|
174
|
+
// New format with warnings
|
|
175
|
+
const mapperResult = result as CommandMapperResult;
|
|
176
|
+
this.warnings.push(...mapperResult.warnings);
|
|
177
|
+
return mapperResult.ast;
|
|
178
|
+
} else {
|
|
179
|
+
// Legacy format (just CommandNode)
|
|
180
|
+
return result as CommandNode;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Fallback: generic command mapping
|
|
185
|
+
return this.buildGenericCommand(node);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Generic command builder when no specific mapper is available.
|
|
190
|
+
* Maps roles to args in a predictable order.
|
|
191
|
+
*/
|
|
192
|
+
private buildGenericCommand(node: CommandSemanticNode): CommandNode {
|
|
193
|
+
const args: ExpressionNode[] = [];
|
|
194
|
+
const modifiers: Record<string, ExpressionNode> = {};
|
|
195
|
+
|
|
196
|
+
// Standard role-to-position mapping
|
|
197
|
+
// Note: Using only valid SemanticRoles from the type definition
|
|
198
|
+
const argRoles: SemanticRole[] = ['patient', 'source', 'quantity'];
|
|
199
|
+
const modifierRoles: SemanticRole[] = ['destination', 'duration', 'method', 'style'];
|
|
200
|
+
|
|
201
|
+
// Convert argument roles
|
|
202
|
+
for (const role of argRoles) {
|
|
203
|
+
const value = node.roles.get(role);
|
|
204
|
+
if (value) {
|
|
205
|
+
args.push(convertValue(value));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Convert modifier roles
|
|
210
|
+
for (const role of modifierRoles) {
|
|
211
|
+
const value = node.roles.get(role);
|
|
212
|
+
if (value) {
|
|
213
|
+
// Map semantic roles to hyperscript modifier keywords
|
|
214
|
+
const modifierKey = this.roleToModifierKey(role);
|
|
215
|
+
modifiers[modifierKey] = convertValue(value);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const result: CommandNode = {
|
|
220
|
+
type: 'command',
|
|
221
|
+
name: node.action,
|
|
222
|
+
args,
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Only add modifiers if there are any (avoid exactOptionalPropertyTypes issue)
|
|
226
|
+
if (Object.keys(modifiers).length > 0) {
|
|
227
|
+
return { ...result, modifiers };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Map semantic roles to hyperscript modifier keywords.
|
|
235
|
+
*/
|
|
236
|
+
private roleToModifierKey(role: SemanticRole): string {
|
|
237
|
+
const mapping: Partial<Record<SemanticRole, string>> = {
|
|
238
|
+
destination: 'on',
|
|
239
|
+
duration: 'for',
|
|
240
|
+
source: 'from',
|
|
241
|
+
condition: 'if',
|
|
242
|
+
method: 'via',
|
|
243
|
+
style: 'with',
|
|
244
|
+
};
|
|
245
|
+
return mapping[role] ?? role;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Build an EventHandlerNode from an EventHandlerSemanticNode.
|
|
250
|
+
*/
|
|
251
|
+
private buildEventHandler(node: EventHandlerSemanticNode): EventHandlerNode {
|
|
252
|
+
// Extract event name(s)
|
|
253
|
+
const eventValue = node.roles.get('event');
|
|
254
|
+
let event: string;
|
|
255
|
+
let events: string[] | undefined;
|
|
256
|
+
|
|
257
|
+
if (eventValue?.type === 'literal') {
|
|
258
|
+
const eventStr = String(eventValue.value);
|
|
259
|
+
// Handle "click or keydown" syntax
|
|
260
|
+
if (eventStr.includes('|') || eventStr.includes(' or ')) {
|
|
261
|
+
events = eventStr.split(/\s+or\s+|\|/).map(e => e.trim());
|
|
262
|
+
event = events[0];
|
|
263
|
+
} else {
|
|
264
|
+
event = eventStr;
|
|
265
|
+
}
|
|
266
|
+
} else if (eventValue?.type === 'reference') {
|
|
267
|
+
event = eventValue.value;
|
|
268
|
+
} else {
|
|
269
|
+
event = 'click'; // Default event
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Build body commands recursively
|
|
273
|
+
const commands = node.body.map(child => this.build(child));
|
|
274
|
+
|
|
275
|
+
// Get selector/target from 'source' role if present
|
|
276
|
+
const fromValue = node.roles.get('source');
|
|
277
|
+
let selector: string | undefined;
|
|
278
|
+
let target: string | undefined;
|
|
279
|
+
|
|
280
|
+
if (fromValue?.type === 'selector') {
|
|
281
|
+
selector = fromValue.value;
|
|
282
|
+
target = fromValue.value;
|
|
283
|
+
} else if (fromValue?.type === 'reference') {
|
|
284
|
+
target = fromValue.value;
|
|
285
|
+
} else if (fromValue?.type === 'literal') {
|
|
286
|
+
target = String(fromValue.value);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Get condition from 'condition' role if present
|
|
290
|
+
const conditionValue = node.roles.get('condition');
|
|
291
|
+
const condition = conditionValue ? convertValue(conditionValue) : undefined;
|
|
292
|
+
|
|
293
|
+
// Get destination (watchTarget) if present
|
|
294
|
+
const destinationValue = node.roles.get('destination');
|
|
295
|
+
const watchTarget = destinationValue ? convertValue(destinationValue) : undefined;
|
|
296
|
+
|
|
297
|
+
// Extract event modifiers
|
|
298
|
+
const modifiers = node.eventModifiers;
|
|
299
|
+
|
|
300
|
+
// Handle queue modifier (debounce, throttle, etc. are runtime concerns)
|
|
301
|
+
let finalSelector = selector;
|
|
302
|
+
if (modifiers?.from) {
|
|
303
|
+
const fromMod = modifiers.from;
|
|
304
|
+
if (fromMod.type === 'selector' && !selector) {
|
|
305
|
+
finalSelector = fromMod.value;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Extract event parameter names for destructuring (e.g., on click(clientX, clientY))
|
|
310
|
+
const args = node.parameterNames ? [...node.parameterNames] : undefined;
|
|
311
|
+
|
|
312
|
+
// Build result with spread for optional properties (exactOptionalPropertyTypes compliant)
|
|
313
|
+
return {
|
|
314
|
+
type: 'eventHandler' as const,
|
|
315
|
+
event,
|
|
316
|
+
commands,
|
|
317
|
+
...(events && events.length > 1 ? { events } : {}),
|
|
318
|
+
...(finalSelector ? { selector: finalSelector } : {}),
|
|
319
|
+
...(target ? { target } : {}),
|
|
320
|
+
...(condition ? { condition: condition as ASTNode } : {}),
|
|
321
|
+
...(watchTarget ? { watchTarget } : {}),
|
|
322
|
+
...(args && args.length > 0 ? { args, params: args } : {}),
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Build a CommandNode from a ConditionalSemanticNode.
|
|
328
|
+
*
|
|
329
|
+
* Produces a command node with:
|
|
330
|
+
* - args[0]: condition expression
|
|
331
|
+
* - args[1]: then block (wrapped in { type: 'block', commands: [...] })
|
|
332
|
+
* - args[2]: else block (optional, same format)
|
|
333
|
+
*
|
|
334
|
+
* This format matches what IfCommand.parseInput() expects.
|
|
335
|
+
*/
|
|
336
|
+
private buildConditional(node: ConditionalSemanticNode): CommandNode {
|
|
337
|
+
const conditionValue = node.roles.get('condition');
|
|
338
|
+
if (!conditionValue) {
|
|
339
|
+
throw new Error('Conditional node missing condition');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const condition = convertValue(conditionValue);
|
|
343
|
+
const thenBranch = node.thenBranch.map(child => this.build(child));
|
|
344
|
+
const elseBranch = node.elseBranch?.map(child => this.build(child));
|
|
345
|
+
|
|
346
|
+
// Build args array matching IfCommand expected format
|
|
347
|
+
const args: ExpressionNode[] = [
|
|
348
|
+
condition,
|
|
349
|
+
// args[1]: then block wrapped as block node
|
|
350
|
+
{
|
|
351
|
+
type: 'block',
|
|
352
|
+
commands: thenBranch,
|
|
353
|
+
} as unknown as ExpressionNode,
|
|
354
|
+
];
|
|
355
|
+
|
|
356
|
+
// args[2]: else block (if present)
|
|
357
|
+
if (elseBranch && elseBranch.length > 0) {
|
|
358
|
+
args.push({
|
|
359
|
+
type: 'block',
|
|
360
|
+
commands: elseBranch,
|
|
361
|
+
} as unknown as ExpressionNode);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return {
|
|
365
|
+
type: 'command',
|
|
366
|
+
name: 'if',
|
|
367
|
+
args,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Build AST nodes from a CompoundSemanticNode.
|
|
373
|
+
*
|
|
374
|
+
* Converts to CommandSequence for runtime compatibility.
|
|
375
|
+
* The runtime recognizes 'CommandSequence' type and executes commands in order.
|
|
376
|
+
*/
|
|
377
|
+
private buildCompound(node: CompoundSemanticNode): ASTNode {
|
|
378
|
+
// Build all statements recursively
|
|
379
|
+
const statements = node.statements.map(child => this.build(child));
|
|
380
|
+
|
|
381
|
+
// Single statement: unwrap and return directly
|
|
382
|
+
if (statements.length === 1) {
|
|
383
|
+
return statements[0];
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Empty: return a no-op block
|
|
387
|
+
if (statements.length === 0) {
|
|
388
|
+
return {
|
|
389
|
+
type: 'block',
|
|
390
|
+
commands: [],
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Convert to CommandSequence for runtime compatibility
|
|
395
|
+
// Runtime handles 'CommandSequence' type in executeCommandSequence()
|
|
396
|
+
const result: CommandSequenceNode = {
|
|
397
|
+
type: 'CommandSequence',
|
|
398
|
+
commands: statements,
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
return result;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Build a CommandNode from a LoopSemanticNode.
|
|
406
|
+
*
|
|
407
|
+
* Produces a 'repeat' command with:
|
|
408
|
+
* - args[0]: loop type identifier (forever, times, for, while, until)
|
|
409
|
+
* - args[1]: count/condition/variable depending on loop type
|
|
410
|
+
* - args[2]: collection (for 'for' loops)
|
|
411
|
+
* - args[last]: body block
|
|
412
|
+
*
|
|
413
|
+
* This format matches what the repeat command parser produces.
|
|
414
|
+
*/
|
|
415
|
+
private buildLoop(node: LoopSemanticNode): CommandNode {
|
|
416
|
+
// Build body commands recursively
|
|
417
|
+
const bodyCommands = node.body.map(child => this.build(child));
|
|
418
|
+
|
|
419
|
+
const args: ExpressionNode[] = [
|
|
420
|
+
// args[0]: loop type identifier
|
|
421
|
+
{
|
|
422
|
+
type: 'identifier',
|
|
423
|
+
name: node.loopVariant,
|
|
424
|
+
} as unknown as ExpressionNode,
|
|
425
|
+
];
|
|
426
|
+
|
|
427
|
+
// Add loop-specific arguments based on variant
|
|
428
|
+
switch (node.loopVariant) {
|
|
429
|
+
case 'times': {
|
|
430
|
+
// args[1]: count expression
|
|
431
|
+
const quantity = node.roles.get('quantity');
|
|
432
|
+
if (quantity) {
|
|
433
|
+
args.push(convertValue(quantity));
|
|
434
|
+
}
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
case 'for': {
|
|
438
|
+
// args[1]: loop variable name
|
|
439
|
+
if (node.loopVariable) {
|
|
440
|
+
args.push({
|
|
441
|
+
type: 'string',
|
|
442
|
+
value: node.loopVariable,
|
|
443
|
+
} as unknown as ExpressionNode);
|
|
444
|
+
}
|
|
445
|
+
// args[2]: collection/source
|
|
446
|
+
const source = node.roles.get('source');
|
|
447
|
+
if (source) {
|
|
448
|
+
args.push(convertValue(source));
|
|
449
|
+
}
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
case 'while':
|
|
453
|
+
case 'until': {
|
|
454
|
+
// args[1]: condition expression
|
|
455
|
+
const condition = node.roles.get('condition');
|
|
456
|
+
if (condition) {
|
|
457
|
+
args.push(convertValue(condition));
|
|
458
|
+
}
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
case 'forever':
|
|
462
|
+
// No additional args needed for forever loops
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// args[last]: body block
|
|
467
|
+
args.push({
|
|
468
|
+
type: 'block',
|
|
469
|
+
commands: bodyCommands,
|
|
470
|
+
} as unknown as ExpressionNode);
|
|
471
|
+
|
|
472
|
+
return {
|
|
473
|
+
type: 'command',
|
|
474
|
+
name: 'repeat',
|
|
475
|
+
args,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Build a BlockNode from an array of semantic nodes.
|
|
481
|
+
* Useful for grouping commands in if/else branches.
|
|
482
|
+
*/
|
|
483
|
+
buildBlock(nodes: SemanticNode[]): BlockNode {
|
|
484
|
+
const commands = nodes.map(child => this.build(child));
|
|
485
|
+
return {
|
|
486
|
+
type: 'block',
|
|
487
|
+
commands,
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// =============================================================================
|
|
493
|
+
// Convenience Function
|
|
494
|
+
// =============================================================================
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Result from building an AST, including any warnings.
|
|
498
|
+
*/
|
|
499
|
+
export interface BuildASTResult {
|
|
500
|
+
ast: ASTNode;
|
|
501
|
+
warnings: string[];
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Build an AST from a SemanticNode using default options.
|
|
506
|
+
*
|
|
507
|
+
* @param node - The semantic node to convert
|
|
508
|
+
* @returns The corresponding AST node and any warnings
|
|
509
|
+
*/
|
|
510
|
+
export function buildAST(node: SemanticNode): BuildASTResult {
|
|
511
|
+
const builder = new ASTBuilder();
|
|
512
|
+
const ast = builder.build(node);
|
|
513
|
+
return {
|
|
514
|
+
ast,
|
|
515
|
+
warnings: builder.warnings,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Re-exports from value-converters
|
|
520
|
+
export {
|
|
521
|
+
convertValue,
|
|
522
|
+
convertLiteral,
|
|
523
|
+
convertSelector,
|
|
524
|
+
convertReference,
|
|
525
|
+
convertPropertyPath,
|
|
526
|
+
convertExpression,
|
|
527
|
+
} from './value-converters';
|
|
528
|
+
|
|
529
|
+
// Re-exports from command-mappers
|
|
530
|
+
export {
|
|
531
|
+
getCommandMapper,
|
|
532
|
+
registerCommandMapper,
|
|
533
|
+
getRegisteredMappers,
|
|
534
|
+
type CommandMapper,
|
|
535
|
+
type CommandMapperResult,
|
|
536
|
+
} from './command-mappers';
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic Value to AST Node Converters
|
|
3
|
+
*
|
|
4
|
+
* Converts SemanticValue types to AST expression nodes.
|
|
5
|
+
* Used by the AST builder to construct expression trees from semantic parsing results.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
SemanticValue,
|
|
10
|
+
LiteralValue,
|
|
11
|
+
SelectorValue,
|
|
12
|
+
ReferenceValue,
|
|
13
|
+
PropertyPathValue,
|
|
14
|
+
ExpressionValue,
|
|
15
|
+
} from '../types';
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
parseExpression,
|
|
19
|
+
type ExpressionNode,
|
|
20
|
+
type LiteralNode,
|
|
21
|
+
type SelectorNode,
|
|
22
|
+
type ContextReferenceNode,
|
|
23
|
+
type PropertyAccessNode,
|
|
24
|
+
type IdentifierNode,
|
|
25
|
+
type ContextType,
|
|
26
|
+
type SelectorKind,
|
|
27
|
+
} from './expression-parser';
|
|
28
|
+
|
|
29
|
+
// =============================================================================
|
|
30
|
+
// Value Converters
|
|
31
|
+
// =============================================================================
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Convert a SemanticValue to an AST ExpressionNode.
|
|
35
|
+
*
|
|
36
|
+
* @param value - The semantic value to convert
|
|
37
|
+
* @param warnings - Optional array to collect warnings about potentially incorrect type choices
|
|
38
|
+
* @returns The corresponding AST expression node
|
|
39
|
+
*/
|
|
40
|
+
export function convertValue(value: SemanticValue, warnings?: string[]): ExpressionNode {
|
|
41
|
+
switch (value.type) {
|
|
42
|
+
case 'literal':
|
|
43
|
+
return convertLiteral(value);
|
|
44
|
+
case 'selector':
|
|
45
|
+
return convertSelector(value, warnings);
|
|
46
|
+
case 'reference':
|
|
47
|
+
return convertReference(value);
|
|
48
|
+
case 'property-path':
|
|
49
|
+
return convertPropertyPath(value, warnings);
|
|
50
|
+
case 'expression':
|
|
51
|
+
return convertExpression(value);
|
|
52
|
+
default:
|
|
53
|
+
// Exhaustive check
|
|
54
|
+
const _exhaustive: never = value;
|
|
55
|
+
throw new Error(`Unknown semantic value type: ${(_exhaustive as SemanticValue).type}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Convert a LiteralValue to a LiteralNode.
|
|
61
|
+
*/
|
|
62
|
+
export function convertLiteral(value: LiteralValue): LiteralNode {
|
|
63
|
+
const result: LiteralNode = {
|
|
64
|
+
type: 'literal',
|
|
65
|
+
value: value.value,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Only add dataType if defined (exactOptionalPropertyTypes)
|
|
69
|
+
if (value.dataType) {
|
|
70
|
+
return { ...result, dataType: value.dataType };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Convert a SelectorValue to a SelectorNode.
|
|
78
|
+
*
|
|
79
|
+
* @param value - The selector value to convert
|
|
80
|
+
* @param warnings - Optional array to collect warnings
|
|
81
|
+
*/
|
|
82
|
+
export function convertSelector(value: SelectorValue, warnings?: string[]): SelectorNode {
|
|
83
|
+
// Warn if selector looks like a CSS property (starts with * followed by a letter/hyphen)
|
|
84
|
+
// This catches cases like "*background-color" which should likely be a literal string
|
|
85
|
+
if (warnings && value.value.startsWith('*') && /^[a-zA-Z-]/.test(value.value.slice(1))) {
|
|
86
|
+
warnings.push(
|
|
87
|
+
`Converted '${value.value}' to a CSS selector, but it looks like a CSS property name. ` +
|
|
88
|
+
`CSS properties in commands like 'transition' should be literal strings, not selectors. ` +
|
|
89
|
+
`Consider using expectedTypes: ['literal'] instead of ['literal', 'selector'] in the command schema.`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
type: 'selector',
|
|
95
|
+
value: value.value,
|
|
96
|
+
selector: value.value,
|
|
97
|
+
selectorType: value.selectorKind as SelectorKind,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Convert a ReferenceValue to a ContextReferenceNode.
|
|
103
|
+
*/
|
|
104
|
+
export function convertReference(value: ReferenceValue): ContextReferenceNode {
|
|
105
|
+
return {
|
|
106
|
+
type: 'contextReference',
|
|
107
|
+
contextType: value.value as ContextType,
|
|
108
|
+
name: value.value,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Convert a PropertyPathValue to a PropertyAccessNode.
|
|
114
|
+
* Recursively converts the object part.
|
|
115
|
+
*
|
|
116
|
+
* @param value - The property path value to convert
|
|
117
|
+
* @param warnings - Optional array to collect warnings
|
|
118
|
+
*/
|
|
119
|
+
export function convertPropertyPath(
|
|
120
|
+
value: PropertyPathValue,
|
|
121
|
+
warnings?: string[]
|
|
122
|
+
): PropertyAccessNode {
|
|
123
|
+
return {
|
|
124
|
+
type: 'propertyAccess',
|
|
125
|
+
object: convertValue(value.object, warnings),
|
|
126
|
+
property: value.property,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Convert an ExpressionValue (raw string) by parsing it with the expression parser.
|
|
132
|
+
* This is the fallback for complex expressions that couldn't be fully parsed
|
|
133
|
+
* at the semantic level.
|
|
134
|
+
*/
|
|
135
|
+
export function convertExpression(value: ExpressionValue): ExpressionNode {
|
|
136
|
+
const result = parseExpression(value.raw);
|
|
137
|
+
|
|
138
|
+
if (!result.success || !result.node) {
|
|
139
|
+
// If parsing fails, return an identifier node with the raw value
|
|
140
|
+
const identifier: IdentifierNode = {
|
|
141
|
+
type: 'identifier',
|
|
142
|
+
name: value.raw,
|
|
143
|
+
};
|
|
144
|
+
return identifier;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return result.node;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// =============================================================================
|
|
151
|
+
// Type Guards
|
|
152
|
+
// =============================================================================
|
|
153
|
+
|
|
154
|
+
export function isLiteralValue(value: SemanticValue): value is LiteralValue {
|
|
155
|
+
return value.type === 'literal';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function isSelectorValue(value: SemanticValue): value is SelectorValue {
|
|
159
|
+
return value.type === 'selector';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function isReferenceValue(value: SemanticValue): value is ReferenceValue {
|
|
163
|
+
return value.type === 'reference';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function isPropertyPathValue(value: SemanticValue): value is PropertyPathValue {
|
|
167
|
+
return value.type === 'property-path';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function isExpressionValue(value: SemanticValue): value is ExpressionValue {
|
|
171
|
+
return value.type === 'expression';
|
|
172
|
+
}
|