Skip to content

Conversation

jeskew
Copy link
Member

@jeskew jeskew commented Aug 14, 2025

Resolves #2922 and resolves #16988

Microsoft Reviewers: Open in CodeFlow

Copy link
Contributor

github-actions bot commented Aug 14, 2025

Test this change out locally with the following install scripts (Action run 17043723403)

VSCode
  • Mac/Linux
    bash <(curl -Ls https://aka.ms/bicep/nightly-vsix.sh) --run-id 17043723403
  • Windows
    iex "& { $(irm https://aka.ms/bicep/nightly-vsix.ps1) } -RunId 17043723403"
Azure CLI
  • Mac/Linux
    bash <(curl -Ls https://aka.ms/bicep/nightly-cli.sh) --run-id 17043723403
  • Windows
    iex "& { $(irm https://aka.ms/bicep/nightly-cli.ps1) } -RunId 17043723403"

Copy link
Contributor

github-actions bot commented Aug 14, 2025

Dotnet Test Results

    90 files   -     45      90 suites   - 45   37m 42s ⏱️ - 20m 5s
12 278 tests  -      9  12 278 ✅  -      9  0 💤 ±0  0 ❌ ±0 
28 311 runs   - 14 142  28 311 ✅  - 14 142  0 💤 ±0  0 ❌ ±0 

Results for commit 648354d. ± Comparison against base commit d5a9da2.

This pull request removes 1905 and adds 651 tests. Note that renamed tests count towards both.

		nestedProp1: 1
		nestedProp2: 2
		prop1: true
		prop2: false
	1
	2
	\$'")
	prop1: true
	prop2: false
…
Bicep.Core.IntegrationTests.AzTypesViaRegistryTests ‑ Bicep_compiler_handles_corrupted_extension_package_gracefully (\u001f�\u0008\u0000\u0000\u0000\u0000\u0000\u0000
�ӽ\u000e�0\u0010\u0000��>E�\u0003@\u000b�VL�]L\|�
g�\u0008\u0012�	���-�q���cb��C�^�;?��v�:ú�%�2��ؘ%����p�\u0008Wo�0\u0005v%�\u001d��\u001e���ږ2�Y?(\Sm�\u0002\u0013�\u0000 T�R�
�\u0010\�l,\u001d��Vڜ��̰�/ͭ�ҋ�����\u000c���tO�m�Y$\u0008\u0007\u0006LF �\u0013f�F���e&�|�\u001f�;��V�\u001a�vX\u001c��6���
>���q\u001cǙ�\u000bQ�2�\u0000\u000c\u0000\u0000,"Value cannot be null. (Parameter 'source')")
Bicep.Core.IntegrationTests.AzTypesViaRegistryTests ‑ Bicep_compiler_handles_corrupted_extension_package_gracefully (\u001f�\u0008\u0000\u0000\u0000\u0000\u0000\u0000
��K\u000e�0\u0010\u0006�=\u0005'(3-ӑ\u0005{�^�Q\u0012\u001f�\u0018\u001e��xw���\u0005�
�����L:m�W�{��r{̫Z\u001aJM,���3I2�>@B��\u0002\u0002��\u0016"�g�dD[7��,��\u000fR��6�"ϐ�Hq�,I�\u0001�7�v��at��)k�Օ����tCC1հ�A�Q����+���\u0000%���hJ�_\u0000�Z��/��?�����\u0004A\u0010\u0004�\u001a�9G��\u0000\u000c\u0000\u0000,"The path: index.json was not found in artifact contents")
Bicep.Core.IntegrationTests.AzTypesViaRegistryTests ‑ Bicep_compiler_handles_corrupted_extension_package_gracefully (\u001f�\u0008\u0000\u0000\u0000\u0000\u0000\u0000
��O\u000b� \u0014\u0000p�}��\u000f�t�i\u0006;\u0004\u001dZ�
��!Mh�Vl\u000b\u0006}��!�ltٟ ��\u0007�\u0003��\u0013{{U��JtQb\u000e�{\u0018��\u0018����\u0006e\u0002Q�F\u0010\u0011`f�ԽW��QV�0����\u000f�玪�L�T\u0000�/�\u0010\u0018d ̘�ع+F�sW�%L�D��Z��&=�J���V���
wE����\u000cQ @x\u0000\u000c("\u001c\u00187�?JO�y�?�(>.���9�bw�\u001fx�,˲��\u0000~C��\u0000\u000c\u0000\u0000,"'7' is an invalid end of a number. Expected a delimiter. Path: $.INVALID_JSON | LineNumber: 0 | BytePositionInLine: 20.")
Bicep.Core.IntegrationTests.AzTypesViaRegistryTests ‑ Bicep_compiler_handles_corrupted_extension_package_gracefully (\u001f�\u0008\u0000\u0000\u0000\u0000\u0000\u0000\u0003�ӽ\u000e�0\u0010\u0007��>\u0005OP�Z�Z\u0007vG_�Q\u0012?B1\u0002������\u0001�`b�c/�����t�M��ŵ�Z�N��\u001a\u0004�e��=$\u0014h^@���\u0008�t�o2��\u001bw
��1�\u0007)���X\u00169\u001a"R��Z\u0012Y�lW��\u001b�arq�!o��W7/Ou���r�a�F����[3>�\u001f@	$ `\u001d>
�����Y2����?�� ��(Z�\u0013\u0015>��\u0000\u000c\u0000\u0000,"The path: index.json was not found in artifact contents")
Bicep.Core.IntegrationTests.AzTypesViaRegistryTests ‑ Bicep_compiler_handles_corrupted_extension_package_gracefully (\u001f�\u0008\u0000\u0000\u0000\u0000\u0000\u0000\u0003��A\u000b�0\u0014\u0000���\u0015�\u000f�o�6
<\u0004\u001d2��k�\u001cd��\u001a\u0008�����tQ\u000b�w�\u001e����Qg���V�.+��s(\u0019\u001a ����-�K��\u000b\u0010��c��\u000c^I�{U�\u0012K�"�\u000fr\u0003K�Y�#���]\u0019����\u0013\u0000r�{��=\u0016Z7U���HuC/յh���o\u001f���~��r|��p}�8p\u0010\u001e�
' �}p�'��?���\u001d'��&^\u001e��mb�-���]�a\u0018�1�'���\u001f\u0000\u000c\u0000\u0000,"'7' is an invalid end of a number. Expected a delimiter. Path: $.INVALID_JSON | LineNumber: 0 | BytePositionInLine: 20.")
Bicep.Core.IntegrationTests.AzTypesViaRegistryTests ‑ Bicep_compiler_handles_corrupted_extension_package_gracefully (\u001f�\u0008\u0000\u0000\u0000\u0000\u0000\u0000\u0003��K\u000e�0\u0010\u0006�=E�\u0001jK�\u0016Lػ1q�\u0001*�\u0011#H\u0000\u0013\u0012��-\u000b�\u0006ↇ����$3}�l�7�\u0016M�Uͤ�䚑�qK\u0005A�zG\u0004�\u0008��	�\u0000����O��^7������\u0007�!5M�c,쥃�C\u00151%C
R��^2�'"Z��\u001cgE�-�Է�+χʗ>�3��~�����.\u0003"�\u0003W�~\u001b \\u0001H��Y2����P�P`[b�`�������'s���l��8�t^�Ĉ/\u0000\u000c\u0000\u0000,"Value cannot be null. (Parameter 'source')")
Bicep.Core.IntegrationTests.DirectResourceCollectionTests ‑ DirectResourceCollectionAccess_NotAllowedWithinLoops ("output loopOutput array = [for i in range(0, 2): {
  prop: map(containerWorkers, (w) => w.properties.ipAddress.ip)
}]")
Bicep.Core.IntegrationTests.DirectResourceCollectionTests ‑ DirectResourceCollectionAccess_NotAllowedWithinLoops ("resource propertyLoop 'Microsoft.ContainerInstance/containerGroups@2022-09-01' = {
  name: 'gh9440-loop'
  location: 'westus'
  properties: {
    containers: [for i in range(0, 2): {
      name: 'gh9440-w1c-${i}'
      properties: {
        command: [
          'echo "${join(map(containerWorkers, (w) => w.properties.ipAddress.ip), ',')}"'
        ]
      }
    }]
  }
}")
Bicep.Core.IntegrationTests.DirectResourceCollectionTests ‑ DirectResourceCollectionAccess_NotAllowedWithinLoops ("var loopVar = [for i in range(0, 2): {
  prop: map(containerWorkers, (w) => w.properties.ipAddress.ip)
}]")
Bicep.Core.IntegrationTests.Emit.ParamsFileWriterTests ‑ Params_file_with_no_errors_should_compile_correctly ("
using 'main.bicep'

// involves all syntax
param myParam = {
  arr: [
    {
      a : 'b'
    }
    {
      c : true
    }
  ]
  name: 'complex object!'
  priority: 3
  val: null
  obj: {
      a: 'b'
      c: [
          'd'
           1
      ]
  }
}","
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "myParam": {
      "value": {
        "arr" : [
          {
            "a" : "b"
          },
          {
            "c" : true
          }
        ],
        "name" : "complex object!",
        "priority" : 3,
        "val" : null,
        "obj" : {
          "a" : "b",
          "c" : [
            "d",
            1
          ]
        }
      }
    }
  }
}","
param myParam object
")
…

♻️ This comment has been updated with latest results.

@jeskew
Copy link
Member Author

jeskew commented Aug 15, 2025

User defined constraints are added in this PR as a runtime-only feature; they will be checked by the ARM engine when the template is deployed, but they are not checked by Bicep at compile time. This was done because we don't have a good way to eval a lambda, and adding such a mechanism (which would also make type inference on map, filter, reduce, etc. better) is a big undertaking. I'm OK with this limitation since the @validate() decorator added by this PR requires a feature flag to use.

@jeskew
Copy link
Member Author

jeskew commented Aug 15, 2025

A second limitation is that while user-defined constraints in ARM support multiple predicates, I couldn't find a way to define a decorator that:

  • Has one required parameter (a lambda predicate)
  • Has an optional string parameter
  • Will accept additional lambda + string pairs

The ARM function will accept a single argument or an even number of arguments, where the even numbered arguments (0-indexed) must be lambdas and the odd numbered arguments must be strings. We don't currently support overloads for decorator functions, which thwarted my plan to fake this by defining three overloads:

  • validate(predicate: lambda)
  • validate(predicate: lambda, errorMessage: string)
  • validate(predicate: lambda, errorMessage: string, secondPredicate: lambda, secondPredicate: string)

and then just adding more overloads in the future as requested.

This limitation also seems fine in an experimental feature.

@jeskew jeskew marked this pull request as ready for review August 15, 2025 00:11
# Conflicts:
#	src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs
@@ -1056,6 +1050,18 @@ private void ValidateDecorators(IEnumerable<DecoratorSyntax> decoratorSyntaxes,

if (decorator is not null)
{
for (int i = 0; i < decoratorSyntax.Arguments.Length; i++)
{
var parameterFlags = decorator.Overload.FixedParameters.Length < i
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be >?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature request: parameter validation decorator Custom decorators
2 participants