| File: Publishing\ManifestExpression.cs | Web Access |
| Project: src\src\Aspire.Hosting\Aspire.Hosting.csproj (Aspire.Hosting) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Aspire.Hosting.Publishing; /// <summary> /// Identifies references supported by the existing manifest expression language. /// </summary> internal static class ManifestExpression { internal readonly record struct Token(int Start, int Length, string Text); public static IEnumerable<Token> GetTokens(string expression) { // Manifest strings contain references such as "https://{infra.outputs.host}". // Doubled braces escape literals: "{{frontend.bindings.http.tlsEnabled}}" is not a reference. // Match azd's scanner: https://github.com/Azure/azure-dev/blob/main/cli/azd/pkg/apphost/eval.go for (var i = 0; i < expression.Length; i++) { if (expression[i] is not ('{' or '}')) { continue; } if (i + 1 < expression.Length && expression[i + 1] == expression[i]) { i++; continue; } if (expression[i] == '}') { throw new FormatException($"Unexpected '}}' in manifest expression at position {i}."); } var end = expression.IndexOf('}', i + 1); if (end < 0) { throw new FormatException($"Unclosed '{{' in manifest expression at position {i}."); } yield return new Token(i, end - i + 1, expression[i..(end + 1)]); i = end; } } public static bool IsSupportedReference(string expression) { // This is a vocabulary check, not a resource-existence check. Resource callbacks own the // referenced inputs/outputs. Keep aligned with azd's evalBindingRef, not CLR provider types: // https://github.com/Azure/azure-dev/blob/main/cli/azd/pkg/apphost/generate.go var parts = expression[1..^1].Split('.'); if (parts.Length < 2) { return false; } if (parts[0].Length == 0) { return parts is ["", "outputs", ..] && parts.Length >= 3 && parts[2].Length > 0; } return parts[1..] switch { ["connectionString"] or ["value"] or ["containerImage"] or ["containerPort"] or ["secretOutputs"] => true, ["inputs", var input] => input.Length > 0, ["outputs" or "secretOutputs" or "secrets", ..] => parts.Length >= 3 && parts[2].Length > 0, ["bindings", var endpoint, "scheme" or "protocol" or "transport" or "external" or "host" or "targetPort" or "port" or "url"] => endpoint.Length > 0, ["bindMounts" or "volumes", var index, "storage"] => int.TryParse(index, out var value) && value >= 0, _ => false }; } }