77
88import static java .lang .String .format ;
99
10+ import java .util .Locale ;
1011import java .util .logging .Logger ;
1112import software .amazon .smithy .codegen .core .Symbol ;
1213import software .amazon .smithy .codegen .core .SymbolProvider ;
1314import software .amazon .smithy .model .Model ;
1415import software .amazon .smithy .model .shapes .ServiceShape ;
1516import software .amazon .smithy .model .shapes .Shape ;
1617import software .amazon .smithy .model .shapes .ShapeVisitor ;
18+ import software .amazon .smithy .model .traits .StringTrait ;
19+ import software .amazon .smithy .model .traits .TitleTrait ;
20+ import software .amazon .smithy .utils .SmithyUnstableApi ;
1721
22+ /**
23+ * Creates documentation Symbols for each shape in the model.
24+ *
25+ * <p>These symbols contain many important pieces of metadata. Particularly
26+ * important are:
27+ *
28+ * <p><ul>
29+ * <li>{@code name}: The name of the symbol will be used as the title for its
30+ * definition section. For services, this defaults to the value of the
31+ * {@code title} trait. For other shapes, it defaults to the shape name including
32+ * any renames from the attached service. For members, the member name is appended
33+ * to the parent with a separating {@code -}.
34+ * <li>{@code definitionFile}: The file in which the documentation for this shape
35+ * should be written. By default these are all written to a single flat directory.
36+ * If this is empty, the shape does not have its own definition section.
37+ * <li>{@link #SHAPE_PROPERTY}: A named Shape property containing the shape that
38+ * the symbol represents. Decorators provided by
39+ * {@link DocIntegration#decorateSymbolProvider} MUST set or preserve this
40+ * property.
41+ * <li>{@link #LINK_ID_PROPERTY}: A named String property containing the string to
42+ * use for the id for links to the shape. In HTML, this would be the {@code id} for
43+ * the tag containing the shape's definition. Given a link id {@code foo}, a link
44+ * to the shape's definition might look like {@code https://example.com/shapes#foo}
45+ * for example. If this or {@code definitionFile} is empty, it is not possible to
46+ * link to the shape.
47+ * </ul>
48+ *
49+ * <p>Decorators provided by {@link DocIntegration#decorateSymbolProvider} MUST set
50+ * these properties or preserve
51+ *
52+ */
53+ @ SmithyUnstableApi
1854public class DocSymbolProvider extends ShapeVisitor .Default <Symbol > implements SymbolProvider {
1955
56+ /**
57+ * The name for a shape symbol's named property containing the shape the symbol
58+ * represents.
59+ *
60+ * <p>Decorators provided by {@link DocIntegration#decorateSymbolProvider} MUST
61+ * preserve this property.
62+ *
63+ * <p>Use {@code symbol.expectProperty(SHAPE_PROPERTY, Shape.class)} to access this
64+ * property.
65+ */
66+ public static final String SHAPE_PROPERTY = "shape" ;
67+
68+ /**
69+ * The name for a shape symbol's named property containing the string to use for
70+ * the id for links to the shape. In HTML, this would be the {@code id} for the tag
71+ * containing the shape's definition. Given a link id {@code foo}, a link to the
72+ * shape's definition might look like {@code https://example.com/shapes#foo} for
73+ * example.
74+ *
75+ * <p>If this or {@code definitionFile} is empty, it is not possible to link to
76+ * the shape.
77+ *
78+ * <p>Use {@code symbol.getProperty(LINK_ID_PROPERTY, String.class)} to access this
79+ * property.
80+ */
81+ public static final String LINK_ID_PROPERTY = "linkId" ;
82+
2083 private static final Logger LOGGER = Logger .getLogger (DocSymbolProvider .class .getName ());
2184
2285 private final Model model ;
@@ -39,26 +102,45 @@ public Symbol toSymbol(Shape shape) {
39102 @ Override
40103 public Symbol serviceShape (ServiceShape shape ) {
41104 return getSymbolBuilder (shape )
42- .definitionFile (getDefinitionFile (serviceShape , shape ))
43- .build ();
105+ .definitionFile (getDefinitionFile (serviceShape , shape ))
106+ .build ();
44107 }
45108
46109 private Symbol .Builder getSymbolBuilder (Shape shape ) {
110+ var name = getShapeName (serviceShape , shape );
47111 return Symbol .builder ()
48- .name (getShapeName (serviceShape , shape ))
49- .putProperty ("shape" , shape );
112+ .name (name )
113+ .putProperty (SHAPE_PROPERTY , shape )
114+ .definitionFile (getDefinitionFile (serviceShape , shape ))
115+ .putProperty (LINK_ID_PROPERTY , getLinkId (name ));
50116 }
51117
52- private static String getDefinitionFile (ServiceShape serviceShape , Shape shape ) {
118+ private String getDefinitionFile (ServiceShape serviceShape , Shape shape ) {
119+ if (shape .isMemberShape ()) {
120+ return getDefinitionFile (serviceShape , model .expectShape (shape .getId ().withoutMember ()));
121+ }
53122 return getDefinitionFile (getShapeName (serviceShape , shape ) + ".md" );
54123 }
55124
56- public static String getDefinitionFile (String filename ) {
125+ public String getDefinitionFile (String filename ) {
57126 return "content/" + filename ;
58127 }
59128
60- private static String getShapeName (ServiceShape serviceShape , Shape shape ) {
61- return shape .getId ().getName (serviceShape );
129+ private String getShapeName (ServiceShape serviceShape , Shape shape ) {
130+ if (shape .isServiceShape ()) {
131+ return shape .getTrait (TitleTrait .class )
132+ .map (StringTrait ::getValue )
133+ .orElse (shape .getId ().getName ());
134+ }
135+ var name = shape .getId ().getName (serviceShape );
136+ if (shape .isMemberShape ()) {
137+ name += "-" + toMemberName (shape .asMemberShape ().get ());
138+ }
139+ return name ;
140+ }
141+
142+ private String getLinkId (String shapeName ) {
143+ return shapeName .toLowerCase (Locale .ENGLISH ).replaceAll ("\\ s" , "-" );
62144 }
63145
64146 // All other shapes don't get generation, so we'll do null checks where this might
0 commit comments