diff --git a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/Symbol.java b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/Symbol.java index 24957b2681c..2360515753b 100644 --- a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/Symbol.java +++ b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/Symbol.java @@ -179,6 +179,73 @@ public String relativize(String namespace) { return this.namespace.equals(namespace) ? name : toString(); } + /** + * Converts the symbol to a {@link SymbolReference} using the given {@code alias}. + * + * @param alias Alias to use to refer to the symbol. + * @param options Variadic array of {@link SymbolReference.Option}s. + * @return Returns the created SymbolReference. + */ + public SymbolReference toReference(String alias, SymbolReference.Option... options) { + return SymbolReference.builder() + .alias(alias) + .symbol(this) + .options(options) + .build(); + } + + /** + * Converts the symbol to a {@link Symbol} that refers to this Symbol + * using a {@link SymbolReference}. This makes it easier to refer to a + * type using an alias but still through a Symbol to be compatible with + * {@link SymbolProvider}. + * + *

The following example creates a Symbol that is referred to as + * "__Document" in code, but is an alias of "foo.Document". + * + *

{@code
+     * Symbol aliasedSymbol = Symbol.builder()
+     *         .name("Document")
+     *         .namespace("foo", ".")
+     *         .build()
+     *         .toReferenceSymbol("__Document");
+     * }
+ * + *

When used with a {@link SymbolWriter}, the writer should add an + * import on "foo.Document" and alias it to "__Document". + * + *

The created symbol uses an empty namespace (""). If this is not + * compatible with specific {@link ImportContainer}s to understand that + * the aliased symbol itself needs no imports, then you can augment the + * symbol with other metadata by instead using {@link #toReferencedSymbolBuilder(String)}. + * + *

Note that this does not work with every programming language. + * For example, Java does not support aliasing whereas TypeScript does. + * + * @param alias Alias to use to refer to the symbol. + * @return Returns the created Symbol. + * @see #toReferencedSymbolBuilder(String) + */ + public Symbol toReferencedSymbol(String alias) { + return toReferencedSymbolBuilder(alias).build(); + } + + /** + * Converts the symbol to a {@link Symbol.Builder} that refers to this + * Symbol using a {@link SymbolReference} via an alias. This makes it + * easier to refer to type using an alias but still use a Symbol to be + * compatible with SymbolProviders. + * + * @param alias Alias to use to refer to the symbol. + * @return Returns a SymbolBuilder that is prepared with the symbol and alias. + * @see #toReferencedSymbol(String) + */ + public Symbol.Builder toReferencedSymbolBuilder(String alias) { + return builder() + .name(alias) + .addReference(toReference(alias, SymbolReference.ContextOption.USE)); + } + /** * Gets the list of symbols that are referenced by this symbol. * diff --git a/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/SymbolTest.java b/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/SymbolTest.java index dad10b4a3e5..49b08fcc9db 100644 --- a/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/SymbolTest.java +++ b/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/SymbolTest.java @@ -16,8 +16,10 @@ package software.amazon.smithy.codegen.core; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -114,4 +116,37 @@ public void canAddDependencies() { assertThat(symbol.getDependencies(), containsInAnyOrder(a, b)); assertThat(symbol.toBuilder().build(), equalTo(symbol)); } + + @Test + public void convertsToAliasedSymbolReference() { + Symbol symbol = Symbol.builder() + .name("foo") + .namespace("bar", ".") + .build(); + SymbolReference reference = symbol.toReference("__foo", SymbolReference.ContextOption.DECLARE); + + assertThat(reference.getSymbol(), is(symbol)); + assertThat(reference.getAlias(), equalTo("__foo")); + assertThat(reference.getOptions(), contains(SymbolReference.ContextOption.DECLARE)); + } + + @Test + public void convertsToAliasedSymbol() { + Symbol symbol = Symbol.builder() + .name("foo") + .namespace("bar", ".") + .build(); + + Symbol symbolRef = symbol.toReferencedSymbol("__foo"); + + SymbolReference ref = SymbolReference.builder() + .alias("__foo") + .symbol(symbol) + .options(SymbolReference.ContextOption.USE) + .build(); + + assertThat(symbolRef.getName(), equalTo("__foo")); + assertThat(symbolRef.getNamespace(), equalTo("")); + assertThat(symbolRef.getReferences(), contains(ref)); + } }