From 2def4f084ad7809bc1672977a0d8422fad01f7f3 Mon Sep 17 00:00:00 2001 From: Jonathan Eskew Date: Tue, 10 Dec 2024 15:46:34 -0500 Subject: [PATCH] Add support for type pointers that refer to something other than a top-level type definition to import closure calculation --- .../CompileTimeImportTests.cs | 119 ++++++++++++++++++ .../CompileTimeImports/ArmTemplateHelpers.cs | 14 +-- 2 files changed, 124 insertions(+), 9 deletions(-) diff --git a/src/Bicep.Core.IntegrationTests/CompileTimeImportTests.cs b/src/Bicep.Core.IntegrationTests/CompileTimeImportTests.cs index c9c48f4e0da..5e04fd53be9 100644 --- a/src/Bicep.Core.IntegrationTests/CompileTimeImportTests.cs +++ b/src/Bicep.Core.IntegrationTests/CompileTimeImportTests.cs @@ -2397,4 +2397,123 @@ public void Symbols_entering_the_import_closure_via_multiple_paths_are_supported result.ExcludingLinterDiagnostics().Should().NotHaveAnyDiagnostics(); } + + [TestMethod] + public void Imports_that_enclose_type_fragments_are_supported() + { + var result = CompilationHelper.Compile( + ("main.bicep", """ + import * as foo from 'mod.json' + """), + ("mod.json", $$""" + { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "languageVersion": "2.0", + "definitions": { + "exported": { + "metadata": { + "{{LanguageConstants.MetadataExportedPropertyName}}": true + }, + "type": "array", + "prefixItems": [ + { + "$ref": "#/definitions/notExported/properties/prop" + } + ], + "items": false + }, + "notExported": { + "type": "object", + "properties": { + "prop": { + "type": "object", + "properties": { + "foo": { + "$ref": "#/parameters/param/additionalProperties" + }, + "bar": { + "$ref": "#/outputs/out/items" + } + } + } + } + } + }, + "parameters": { + "param": { + "type": "object", + "additionalProperties": { + "type": "int" + } + } + }, + "outputs": { + "out": { + "type": "array", + "items": { + "type": "bool" + }, + "value": [true] + } + }, + "resources": {} + } + """)); + + result.ExcludingLinterDiagnostics().Should().NotHaveAnyDiagnostics(); + result.Template.Should().HaveValueAtPath("definitions", JToken.Parse($$""" + { + "_1._2": { + "type": "object", + "properties": { + "foo": { + "$ref": "#/definitions/_1._4" + }, + "bar": { + "$ref": "#/definitions/_1._3" + } + }, + "metadata": { + "{{LanguageConstants.MetadataImportedFromPropertyName}}": { + "sourceTemplate": "mod.json", + "originalIdentifier": "#/definitions/notExported/properties/prop" + } + } + }, + "_1._3": { + "type": "bool", + "metadata": { + "{{LanguageConstants.MetadataImportedFromPropertyName}}": { + "sourceTemplate": "mod.json", + "originalIdentifier": "#/outputs/out/items" + } + } + }, + "_1._4": { + "type": "int", + "metadata": { + "{{LanguageConstants.MetadataImportedFromPropertyName}}": { + "sourceTemplate": "mod.json", + "originalIdentifier": "#/parameters/param/additionalProperties" + } + } + }, + "_1.exported": { + "type": "array", + "prefixItems": [ + { + "$ref": "#/definitions/_1._2" + } + ], + "items": false, + "metadata": { + "{{LanguageConstants.MetadataImportedFromPropertyName}}": { + "sourceTemplate": "mod.json" + } + } + } + } + """)); + } } diff --git a/src/Bicep.Core/Emit/CompileTimeImports/ArmTemplateHelpers.cs b/src/Bicep.Core/Emit/CompileTimeImports/ArmTemplateHelpers.cs index 36d64b4411d..e9dc4b9a690 100644 --- a/src/Bicep.Core/Emit/CompileTimeImports/ArmTemplateHelpers.cs +++ b/src/Bicep.Core/Emit/CompileTimeImports/ArmTemplateHelpers.cs @@ -1,24 +1,20 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. + using Azure.Deployments.Core.Definitions.Schema; +using Azure.Deployments.Templates.Engines; namespace Bicep.Core.Emit.CompileTimeImports; internal static class ArmTemplateHelpers { - private const string ArmTypeRefPrefix = "#/definitions/"; - internal static ITemplateSchemaNode DereferenceArmType(SchemaValidationContext context, string typePointer) { - // TODO make LocalSchemaRefResolver in Azure.Deployments.Templates public - if (!typePointer.StartsWith(ArmTypeRefPrefix) || - typePointer[ArmTypeRefPrefix.Length..].Contains('/') || - context.Definitions is null || - !context.Definitions.TryGetValue(typePointer[ArmTypeRefPrefix.Length..], out var typeDefinition)) + if (LocalSchemaRefResolver.ResolveLocalReference(context, typePointer, out var node, out var failureMessage)) { - throw new InvalidOperationException($"Invalid ARM template type reference ({typePointer}) encountered"); + return node; } - return typeDefinition; + throw new InvalidOperationException($"Invalid ARM template type reference ({typePointer}) encountered: {failureMessage}"); } }