You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: support variable parameter counts with type validation in molang queries (#79)
## Issue/Feature Request/Bug report
- Fixes#68
## Changes
Molang queries like `query.is_owner_identifier_any` and
`query.equipped_item_all_tags` accept variable numbers of arguments (n ≥
minimum), but the diagnoser was enforcing exact parameter counts and not
validating parameter types.
**Core data model** (`packages/molang/src/data/molang-function.ts`):
- Added `repeatable?: boolean` field to `MolangParameter` interface to
mark parameters that can be repeated indefinitely
- Removed complex `minParams` and `repeatableParam` fields from
`MolangFunction` interface in favor of simpler per-parameter approach
**Query definitions** (`packages/molang/src/data/general.ts`):
- Updated 16 queries with type annotations and `repeatable: true` on the
last parameter:
- Entity queries: `is_owner_identifier_any`, `is_name_any` (type:
string, repeatable)
- Equipment: `equipped_item_all_tags`, `equipped_item_any_tag` (slot:
string, tag: string repeatable)
- Block position + tags: `block_has_all_tags`,
`block_neighbor_has_all_tags`, etc (xyz: float, tag: string repeatable)
- Client: `graphics_mode_is_any`, `last_input_mode_is_any` (mode: string
repeatable)
- Item: `is_item_name_any` (slot: string, index: float, item: string
repeatable)
- Biome: `entity_biome_has_all_tags`, `entity_biome_has_any_tags`, etc
(tag/identifier: string repeatable)
**Diagnostics**
(`packages/bedrock-diagnoser/src/diagnostics/molang/expressions.ts`):
- Updated validation to detect if the last parameter has `repeatable:
true`
- When repeatable parameter exists, validates minimum parameter count
equals `parameters.length`
- Added parameter type validation for both fixed and repeatable
parameters
- Validates argument types match expected types (string, float, boolean)
- Provides detailed error messages: "wrong argument type at position X,
expected Y but got Z"
- Falls back to exact count check when no repeatable parameter exists
(backward compatible)
## Examples
**Before:**
```javascript
q.is_owner_identifier_any('zombie', 'skeleton', 'creeper')
// ❌ Error: expected 2 arguments but got 3
q.block_has_all_tags(0, 0, 0, 2, 1)
// ✅ No validation error (incorrect!)
```
**After:**
```javascript
q.is_owner_identifier_any('zombie', 'skeleton', 'creeper') // ✅
q.equipped_item_all_tags('slot.weapon.mainhand', 'tag1', 'tag2', 'tag3') // ✅
q.block_has_all_tags(0, 0, 0, 'stone', 'solid') // ✅
q.block_has_all_tags(0, 0, 0, 2, 1)
// ❌ Error: wrong argument type at position 4, expected string but got float
```
**New structure:**
```typescript
{
id: 'equipped_item_all_tags',
parameters: [
{ id: 'slot_name', type: 'string' },
{ id: 'tag', type: 'string', repeatable: true }
]
}
```
## Checklist
- [x] It can build
- [x] The tests are passing (530 tests across packages)
- [x] Code has been reviewed
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>feat: additional molang parameter support</issue_title>
>
<issue_description>https://github.com/Xterionix/minecraft-bedrock-language-server/blob/main/packages/molang/src/data/general.ts#L1199
>
> I'm thinking the solution could be either optional args or, the better
option, allowing a query to essentially take n >= c amount of a certain
argument.
>
> `query.equipped_item_all_tags` follows a similar format
>
> ```
> query.equipped_item_all_tags('slot.name', tag1, tag2, tag3, tag4 ...)
> ```</issue_description>
>
> <agent_instructions>Can you update the molang data structure to allows
for specifiying the minimum amount of parameters, and then update the
diagnoser to check this value? so we can support parameters that can
have an inifite amount</agent_instructions>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> <comment_new><author>@DaanV2</author><body>
> Think that a parameter on the query would be good enough for this 👍
easy to check in the diagnoser</body></comment_new>
> <comment_new><author>@DaanV2</author><body>
> Im going to do something bold (I want to test it), going to see if I
can have copilot do it</body></comment_new>
> </comments>
>
</details>
- Fixes#68
<!-- START COPILOT CODING AGENT TIPS -->
---
💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).
---------
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: DaanV2 <[email protected]>
Copy file name to clipboardExpand all lines: packages/molang/src/data/general.ts
+67-14Lines changed: 67 additions & 14 deletions
Original file line number
Diff line number
Diff line change
@@ -446,18 +446,23 @@ export namespace General {
446
446
{
447
447
id: 'x',
448
448
documentation: 'World-origin-relative position on the x axis',
449
+
type: 'float',
449
450
},
450
451
{
451
452
id: 'y',
452
453
documentation: 'World-origin-relative position on the y axis',
454
+
type: 'float',
453
455
},
454
456
{
455
457
id: 'z',
456
458
documentation: 'World-origin-relative position on the z axis',
459
+
type: 'float',
457
460
},
458
461
{
459
462
id: 'tag',
460
-
documentation: 'The first tag',
463
+
documentation: 'tag name to check',
464
+
type: 'string',
465
+
repeatable: true,
461
466
},
462
467
],
463
468
},
@@ -469,18 +474,23 @@ export namespace General {
469
474
{
470
475
id: 'x',
471
476
documentation: 'World-origin-relative position on the x axis',
477
+
type: 'float',
472
478
},
473
479
{
474
480
id: 'y',
475
481
documentation: 'World-origin-relative position on the y axis',
482
+
type: 'float',
476
483
},
477
484
{
478
485
id: 'z',
479
486
documentation: 'World-origin-relative position on the z axis',
487
+
type: 'float',
480
488
},
481
489
{
482
490
id: 'tag',
483
-
documentation: 'The first tag',
491
+
documentation: 'tag name to check',
492
+
type: 'string',
493
+
repeatable: true,
484
494
},
485
495
],
486
496
},
@@ -492,18 +502,23 @@ export namespace General {
492
502
{
493
503
id: 'x',
494
504
documentation: 'block-relative position on the x axis',
505
+
type: 'float',
495
506
},
496
507
{
497
508
id: 'y',
498
509
documentation: 'block-relative position on the y axis',
510
+
type: 'float',
499
511
},
500
512
{
501
513
id: 'z',
502
514
documentation: 'block-relative position on the z axis',
515
+
type: 'float',
503
516
},
504
517
{
505
518
id: 'tag',
506
-
documentation: 'The first tag',
519
+
documentation: 'tag name to check',
520
+
type: 'string',
521
+
repeatable: true,
507
522
},
508
523
],
509
524
},
@@ -515,18 +530,23 @@ export namespace General {
515
530
{
516
531
id: 'x',
517
532
documentation: 'block-relative position on the x axis',
533
+
type: 'float',
518
534
},
519
535
{
520
536
id: 'y',
521
537
documentation: 'block-relative position on the y axis',
538
+
type: 'float',
522
539
},
523
540
{
524
541
id: 'z',
525
542
documentation: 'block-relative position on the z axis',
543
+
type: 'float',
526
544
},
527
545
{
528
546
id: 'tag',
529
-
documentation: 'The first tag',
547
+
documentation: 'tag name to check',
548
+
type: 'string',
549
+
repeatable: true,
530
550
},
531
551
],
532
552
},
@@ -731,11 +751,19 @@ export namespace General {
731
751
id: 'equipped_item_all_tags',
732
752
documentation:
733
753
"takes a slot name followed by any tag you want to check for in the form of 'tag_name' and returns 1 if all of the tags are on that equipped item, 0 otherwise",
{id: 'tag',documentation: 'tag name to check',type: 'string',repeatable: true},
757
+
],
734
758
},
735
759
{
736
760
id: 'equipped_item_any_tag',
737
761
documentation:
738
762
"takes a slot name followed by any tag you want to check for in the form of 'tag_name' and returns 0 if none of the tags are on that equipped item or 1 if at least 1 tag exists",
{id: 'tag',documentation: 'tag name to check',type: 'string',repeatable: true},
766
+
],
739
767
},
740
768
{
741
769
id: 'equipped_item_is_attachable',
@@ -783,6 +811,9 @@ export namespace General {
783
811
id: 'graphics_mode_is_any',
784
812
documentation:
785
813
"Takes in one or more arguments ('simple', 'fancy', 'deferred', 'raytraced'). If the graphics mode of the client matches any of the arguments, return 1.0. Available on the Client (Resource Packs) only.",
"Takes an equipment slot name (see the replaceitem command) and an optional slot index value. After that, takes one or more full name (with 'namespace:') strings to check for. Returns 1.0 if an item in the specified slot has any of the specified names, otherwise returns 0.0. An empty string '' can be specified to check for an empty slot. Note that querying slot.enderchest, slot.saddle, slot.armor, or slot.chest will only work in behavior packs. A preferred query to query.get_equipped_item_name, as it can be adjusted by Mojang to avoid breaking content if names are changed.",
{id: 'slot_index',documentation: 'optional slot index value',type: 'float'},
1158
+
{id: 'item',documentation: 'item name to check',type: 'string',repeatable: true},
1128
1159
],
1129
1160
},
1130
1161
@@ -1170,8 +1201,7 @@ export namespace General {
1170
1201
documentation:
1171
1202
"Takes one or more arguments. If the entity's name is any of the specified string values, returns 1.0. Otherwise returns 0.0. A preferred query to query.get_name, as it can be adjusted by Mojang to avoid breaking content if names are changed.",
'Takes one or more arguments. Returns whether the root actor identifier is any of the specified strings. A preferred query to query.owner_identifier, as it can be adjusted by Mojang to avoid breaking content if names are changed.',
"Takes one or more arguments ('keyboard_and_mouse', 'touch', or 'gamepad'). If the last input used is any of the specified string values, returns 1.0. Otherwise returns 0.0. Available on the Client (Resource Packs) only.",
1432
+
parameters: [
1433
+
{id: 'mode',documentation: "input mode ('keyboard_and_mouse', 'touch', or 'gamepad')",type: 'string',repeatable: true},
1434
+
],
1403
1435
},
1404
1436
{
1405
1437
id: 'lie_amount',
@@ -1527,11 +1559,23 @@ export namespace General {
1527
1559
id: 'relative_block_has_all_tags',
1528
1560
documentation:
1529
1561
'Takes an entity-relative position and one or more tag names, and returns either 0 or 1 based on if the block at that position has all of the tags provided.',
1562
+
parameters: [
1563
+
{id: 'x',documentation: 'entity-relative position on the x axis',type: 'float'},
1564
+
{id: 'y',documentation: 'entity-relative position on the y axis',type: 'float'},
1565
+
{id: 'z',documentation: 'entity-relative position on the z axis',type: 'float'},
1566
+
{id: 'tag',documentation: 'tag name to check',type: 'string',repeatable: true},
1567
+
],
1530
1568
},
1531
1569
{
1532
1570
id: 'relative_block_has_any_tag',
1533
1571
documentation:
1534
1572
'Takes an entity-relative position and one or more tag names, and returns either 0 or 1 based on if the block at that position has any of the tags provided.',
1573
+
parameters: [
1574
+
{id: 'x',documentation: 'entity-relative position on the x axis',type: 'float'},
1575
+
{id: 'y',documentation: 'entity-relative position on the y axis',type: 'float'},
1576
+
{id: 'z',documentation: 'entity-relative position on the z axis',type: 'float'},
1577
+
{id: 'tag',documentation: 'tag name to check',type: 'string',repeatable: true},
1578
+
],
1535
1579
},
1536
1580
{
1537
1581
id: 'ride_body_x_rotation',
@@ -1750,15 +1794,24 @@ export namespace General {
1750
1794
// Experimental
1751
1795
{
1752
1796
id: 'entity_biome_has_all_tags',
1753
-
documentation: '(EXPERIMENTAL) Compares the biome the entity is standing in with one or more tag names, and returns either 0 or 1 based on if all of the tag names match. Only supported in resource packs (client-side).'
1797
+
documentation: '(EXPERIMENTAL) Compares the biome the entity is standing in with one or more tag names, and returns either 0 or 1 based on if all of the tag names match. Only supported in resource packs (client-side).',
1798
+
parameters: [
1799
+
{id: 'tag',documentation: 'biome tag name to check',type: 'string',repeatable: true},
1800
+
],
1754
1801
},
1755
1802
{
1756
1803
id: 'entity_biome_has_any_identifier',
1757
-
documentation: '(EXPERIMENTAL) Compares the biome the entity is standing in with one or more identifier names, and returns either 0 or 1 based on if any of the identifier names match. Only supported in resource packs (client-side).'
1804
+
documentation: '(EXPERIMENTAL) Compares the biome the entity is standing in with one or more identifier names, and returns either 0 or 1 based on if any of the identifier names match. Only supported in resource packs (client-side).',
1805
+
parameters: [
1806
+
{id: 'identifier',documentation: 'biome identifier to check',type: 'string',repeatable: true},
1807
+
],
1758
1808
},
1759
1809
{
1760
1810
id: 'entity_biome_has_any_tags',
1761
-
documentation: '(EXPERIMENTAL) Compares the biome the entity is standing in with one or more tag names, and returns either 0 or 1 based on if any of the tag names match. Only supported in resource packs (client-side).'
1811
+
documentation: '(EXPERIMENTAL) Compares the biome the entity is standing in with one or more tag names, and returns either 0 or 1 based on if any of the tag names match. Only supported in resource packs (client-side).',
1812
+
parameters: [
1813
+
{id: 'tag',documentation: 'biome tag name to check',type: 'string',repeatable: true},
0 commit comments