1+ /*
2+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+ * SPDX-License-Identifier: Apache-2.0
4+ */
5+ package software .amazon .smithy .python .aws .codegen ;
6+
7+ import software .amazon .smithy .model .traits .InputTrait ;
8+ import software .amazon .smithy .model .traits .OutputTrait ;
9+ import software .amazon .smithy .python .codegen .GenerationContext ;
10+ import software .amazon .smithy .python .codegen .integrations .PythonIntegration ;
11+ import software .amazon .smithy .python .codegen .sections .*;
12+ import software .amazon .smithy .python .codegen .writer .PythonWriter ;
13+ import software .amazon .smithy .utils .CodeInterceptor ;
14+ import software .amazon .smithy .utils .CodeSection ;
15+
16+ import java .util .ArrayList ;
17+ import java .util .List ;
18+
19+ public class AwsRstDocFileGenerator implements PythonIntegration {
20+
21+ @ Override
22+ public List <? extends CodeInterceptor <? extends CodeSection , PythonWriter >> interceptors (
23+ GenerationContext context
24+ ) {
25+ return List .of (
26+ new OperationGenerationInterceptor (context ),
27+ new StructureGenerationInterceptor (context ),
28+ new ErrorGenerationInterceptor (context ),
29+ new UnionGenerationInterceptor (context ),
30+ new UnionMemberGenerationInterceptor (context )
31+ );
32+ }
33+
34+ /**
35+ * Utility method to generate a header for documentation files.
36+ *
37+ * @param title The title of the section.
38+ * @return A formatted header string.
39+ */
40+ private static String generateHeader (String title ) {
41+ return String .format ("%s\n %s\n \n " , title , "=" .repeat (title .length ()));
42+ }
43+
44+ private static final class OperationGenerationInterceptor
45+ implements CodeInterceptor .Appender <OperationSection , PythonWriter > {
46+
47+ private final GenerationContext context ;
48+
49+ public OperationGenerationInterceptor (GenerationContext context ) {
50+ this .context = context ;
51+ }
52+
53+ @ Override
54+ public Class <OperationSection > sectionType () {
55+ return OperationSection .class ;
56+ }
57+
58+ @ Override
59+ public void append (PythonWriter pythonWriter , OperationSection section ) {
60+ var operation = section .operation ();
61+ var operationSymbol = context .symbolProvider ().toSymbol (operation );
62+ var input = context .model ().expectShape (operation .getInputShape ());
63+ var inputSymbol = context .symbolProvider ().toSymbol (input );
64+ var output = context .model ().expectShape (operation .getOutputShape ());
65+ var outputSymbol = context .symbolProvider ().toSymbol (output );
66+
67+ String operationName = operationSymbol .getName ();
68+ String inputSymbolName = inputSymbol .toString ();
69+ String outputSymbolName = outputSymbol .toString ();
70+ String serviceName = context .symbolProvider ().toSymbol (section .service ()).getName ();
71+ String docsFileName = String .format ("docs/client/%s.rst" , operationName );
72+ String fullOperationReference = String .format ("%s.client.%s.%s" ,
73+ context .settings ().moduleName (),
74+ serviceName ,
75+ operationName );
76+
77+ context .writerDelegator ().useFileWriter (docsFileName , "" , fileWriter -> {
78+ fileWriter .write (generateHeader (operationName ));
79+ fileWriter .write (".. automethod:: " + fullOperationReference + "\n \n " );
80+ fileWriter .write (".. toctree::\n :hidden:\n :maxdepth: 2\n \n " );
81+ fileWriter .write ("=================\n Input:\n =================\n \n " );
82+ fileWriter .write (".. autoclass:: " + inputSymbolName + "\n :members:\n " );
83+ fileWriter .write ("=================\n Output:\n =================\n \n " );
84+ fileWriter .write (".. autoclass:: " + outputSymbolName + "\n :members:\n " );
85+ });
86+ }
87+ }
88+
89+ private static final class StructureGenerationInterceptor
90+ implements CodeInterceptor .Appender <StructureSection , PythonWriter > {
91+
92+ private final GenerationContext context ;
93+
94+ public StructureGenerationInterceptor (GenerationContext context ) {
95+ this .context = context ;
96+ }
97+
98+ @ Override
99+ public Class <StructureSection > sectionType () {
100+ return StructureSection .class ;
101+ }
102+
103+ @ Override
104+ public void append (PythonWriter pythonWriter , StructureSection section ) {
105+ var shape = section .structure ();
106+ var symbol = context .symbolProvider ().toSymbol (shape );
107+ String docsFileName = String .format ("docs/models/%s.rst" ,
108+ symbol .getName ());
109+ if (!shape .hasTrait (InputTrait .class ) && !shape .hasTrait (OutputTrait .class )) {
110+ context .writerDelegator ().useFileWriter (docsFileName , "" , writer -> {
111+ writer .write (generateHeader (symbol .getName ()));
112+ writer .write (".. autoclass:: " + symbol .toString () + "\n :members:\n " );
113+ });
114+ }
115+ }
116+ }
117+
118+ private static final class ErrorGenerationInterceptor
119+ implements CodeInterceptor .Appender <ErrorSection , PythonWriter > {
120+
121+ private final GenerationContext context ;
122+
123+ public ErrorGenerationInterceptor (GenerationContext context ) {
124+ this .context = context ;
125+ }
126+
127+ @ Override
128+ public Class <ErrorSection > sectionType () {
129+ return ErrorSection .class ;
130+ }
131+
132+ @ Override
133+ public void append (PythonWriter pythonWriter , ErrorSection section ) {
134+ var symbol = section .errorSymbol ();
135+ String docsFileName = String .format ("docs/models/%s.rst" ,
136+ symbol .getName ());
137+ context .writerDelegator ().useFileWriter (docsFileName , "" , writer -> {
138+ writer .write (generateHeader (symbol .getName ()));
139+ writer .write (".. autoexception:: " + symbol .toString () + "\n :members:\n :show-inheritance:\n " );
140+ });
141+ }
142+ }
143+
144+ private static final class UnionGenerationInterceptor
145+ implements CodeInterceptor .Appender <UnionSection , PythonWriter > {
146+
147+ private final GenerationContext context ;
148+
149+ public UnionGenerationInterceptor (GenerationContext context ) {
150+ this .context = context ;
151+ }
152+
153+ @ Override
154+ public Class <UnionSection > sectionType () {
155+ return UnionSection .class ;
156+ }
157+
158+ @ Override
159+ public void append (PythonWriter pythonWriter , UnionSection section ) {
160+ String parentName = section .parentName ();
161+ ArrayList <String > memberNames = section .memberNames ();
162+ String docsFileName = String .format ("docs/models/%s.rst" , parentName );
163+ context .writerDelegator ().useFileWriter (docsFileName , "" , writer -> {
164+ writer .write (".. _" + parentName + ":\n \n " );
165+ writer .write (generateHeader (parentName ));
166+ writer .write (".. autodata:: " + context .symbolProvider ().toSymbol (section .unionShape ()).toString () + " \n " );
167+ });
168+ }
169+ }
170+
171+ private static final class UnionMemberGenerationInterceptor
172+ implements CodeInterceptor .Appender <UnionMemberSection , PythonWriter > {
173+
174+ private final GenerationContext context ;
175+
176+ public UnionMemberGenerationInterceptor (GenerationContext context ) {
177+ this .context = context ;
178+ }
179+
180+ @ Override
181+ public Class <UnionMemberSection > sectionType () {
182+ return UnionMemberSection .class ;
183+ }
184+
185+ @ Override
186+ public void append (PythonWriter pythonWriter , UnionMemberSection section ) {
187+ var memberSymbol = section .memberSymbol ();
188+ String symbolName = memberSymbol .getName ();
189+ String docsFileName = String .format ("docs/models/%s.rst" , symbolName );
190+ context .writerDelegator ().useFileWriter (docsFileName , "" , writer -> {
191+ writer .write (".. _" + symbolName + ":\n \n " );
192+ writer .write (generateHeader (symbolName ));
193+ writer .write (".. autoclass:: " + memberSymbol .toString () + " \n " );
194+ });
195+ }
196+ }
197+ }
0 commit comments