@@ -7,20 +7,26 @@ import {
77 Declaracao ,
88 Expressao ,
99 Chamada ,
10+ AcessoMetodo ,
1011 AcessoMetodoOuPropriedade ,
1112 Decorador ,
1213 Literal ,
1314 Vetor ,
1415 ConstrutoInterface
1516} from '@designliquido/delegua' ;
17+ import { LexadorPitugues } from '@designliquido/delegua/lexador' ;
1618import { Importador } from '@designliquido/delegua-node/importador' ;
17- import { AvaliadorSintaticoComImportacao } from '@designliquido/delegua-node/avaliador-sintatico/avaliador-sintatico-com-importacao' ;
19+ import {
20+ AvaliadorSintaticoComImportacao
21+ } from '@designliquido/delegua-node/avaliador-sintatico/avaliador-sintatico-com-importacao' ;
1822
1923import { RotaOpenApi } from './rota-open-api' ;
2024import { MetodoHttpOpenApi } from './metodo-http-open-api' ;
2125import { RespostaOpenApi } from './resposta-open-api' ;
2226import { DocumentoOpenApi } from './documento-open-api' ;
23- import { AutoDocumentadorInterface } from '../../interfaces/auto-documentador-interface' ;
27+ import {
28+ AutoDocumentadorInterface
29+ } from '../../interfaces/auto-documentador-interface' ;
2430
2531/**
2632 * O auto documentador lê o projeto e gera uma especificação OpenAPI
@@ -38,7 +44,9 @@ export class AutoDocumentador implements AutoDocumentadorInterface {
3844
3945 constructor ( ) {
4046 this . erros = [ ] ;
41- this . diretorioRotas = caminho . join ( process . cwd ( ) , 'rotas/rest' ) . replace ( / \\ / gi, '/' ) ;
47+ this . diretorioRotas = caminho
48+ . join ( process . cwd ( ) , 'rotas' )
49+ . replace ( / \\ / gi, '/' ) ;
4250
4351 this . decoradoresValidos = {
4452 '@rest.documentacao' : {
@@ -61,11 +69,17 @@ export class AutoDocumentador implements AutoDocumentadorInterface {
6169 }
6270
6371 // TODO: Pensar em como fazer isso considerando importações de outros arquivos.
64- protected async obterEstruturasDeAltoNivelDeControlador ( caminhoControlador : string ) : Promise < Declaracao [ ] > {
72+ protected async obterEstruturasDeAltoNivelDeControlador (
73+ caminhoControlador : string
74+ ) : Promise < Declaracao [ ] > {
6575 const arquivosAbertos = { } ;
6676 const conteudoArquivosAbertos = { } ;
6777
68- const importador = new Importador ( new Lexador ( ) , arquivosAbertos , conteudoArquivosAbertos , false ) ;
78+ const lexador = caminhoControlador . endsWith ( '.pitu' )
79+ ? new LexadorPitugues ( )
80+ : new Lexador ( ) ;
81+
82+ const importador = new Importador ( lexador , arquivosAbertos , conteudoArquivosAbertos , false ) ;
6983
7084 const avaliadorSintatico = new AvaliadorSintaticoComImportacao ( importador ) ;
7185
@@ -84,45 +98,67 @@ export class AutoDocumentador implements AutoDocumentadorInterface {
8498 }
8599
86100 protected async encontrarControladores ( ) {
87- const formatoGlob = ( this . diretorioRotas + '/**/*.delegua' ) . replace ( / \\ / gi, '/' ) ;
88- const arquivos = await glob ( [ formatoGlob ] , { dot : true , absolute : false , stats : false } ) ;
101+ const formatoGlob = (
102+ this . diretorioRotas + '/**/*.{delegua,pitu}'
103+ ) . replace ( / \\ / gi, '/' ) ;
104+ const arquivos = await glob (
105+ [ formatoGlob ] ,
106+ { dot : true , absolute : false , stats : false }
107+ ) ;
89108
90109 const controladores = [ ] ;
110+
91111 for ( const caminhoArquivo of arquivos ) {
92- const estruturas = await this . obterEstruturasDeAltoNivelDeControlador ( caminhoArquivo ) ;
93- const rotaEControlador = this . lerControlador ( caminhoArquivo , estruturas ) ;
112+ const estruturas = await this
113+ . obterEstruturasDeAltoNivelDeControlador ( caminhoArquivo ) ;
114+ const rotaEControlador = this . lerControlador (
115+ caminhoArquivo ,
116+ estruturas
117+ ) ;
118+
94119 controladores . push ( rotaEControlador ) ;
95120 }
96121
97122 return controladores ;
98123 }
99124
100- protected resolverConstrutoValorDecorador ( construtoValor : ConstrutoInterface ) : any {
101- switch ( construtoValor . constructor . name ) {
102- case 'Literal' :
103- return ( construtoValor as Literal ) . valor ;
104- case 'Vetor' :
125+ protected resolverConstrutoValorDecorador (
126+ construtoValor : ConstrutoInterface
127+ ) : any {
128+ switch ( construtoValor . constructor ) {
129+ case Literal :
130+ return construtoValor . valor ;
131+ case Vetor :
105132 const valoresResolvidos = [ ] ;
133+
106134 for ( const valor of ( construtoValor as Vetor ) . valores ) {
107- valoresResolvidos . push ( this . resolverConstrutoValorDecorador ( valor ) ) ;
135+ valoresResolvidos . push (
136+ this . resolverConstrutoValorDecorador ( valor )
137+ ) ;
108138 }
109139
110140 return valoresResolvidos ;
111141 }
112142 }
113143
114- protected resolverAtributosDecorador ( decorador : Decorador ) : Record < string , any > {
144+ protected resolverAtributosDecorador (
145+ decorador : Decorador
146+ ) : Record < string , any > {
115147 const decoradorResolvido : Record < string , any > = { } ;
148+
116149 for ( const [ nomeAtributo , valorAtributo ] of Object . entries ( decorador . atributos ) ) {
117150 decoradorResolvido [ nomeAtributo ] = this . resolverConstrutoValorDecorador ( valorAtributo ) ;
118151 }
119152
120153 return decoradorResolvido ;
121154 }
122155
123- protected resolverDecoradorDocumentacao ( atributos : Record < string , any > ) : RotaOpenApi {
156+ protected resolverDecoradorDocumentacao (
157+ atributos : Record < string , any >
158+ ) : RotaOpenApi {
124159 const retorno : RotaOpenApi = { } ;
125160 const decoradoresValidosDocumentacao = this . decoradoresValidos [ '@rest.documentacao' ] ;
161+
126162 for ( const [ nomeAtributo , valorAtributo ] of Object . entries ( atributos ) ) {
127163 retorno [ decoradoresValidosDocumentacao [ nomeAtributo ] as keyof RotaOpenApi ] = valorAtributo ;
128164 }
@@ -132,18 +168,21 @@ export class AutoDocumentador implements AutoDocumentadorInterface {
132168
133169 protected resolverDecoradorResposta ( atributos : Record < string , any > ) : any {
134170 const decoradoresValidosResposta = this . decoradoresValidos [ '@rest.resposta' ] ;
171+
135172 if ( ! ( 'codigo' in atributos ) && ! ( 'código' in atributos ) ) {
136- this . erros . push ( new Error ( `Decorador @rest.resposta não possui atributo obrigado 'código' ou 'codigo'.` ) ) ;
173+ this . erros . push ( new Error (
174+ `Decorador @rest.resposta não possui atributo obrigado 'código' ou 'codigo'.`
175+ ) ) ;
176+
137177 return null ;
138178 }
139179
140180 const codigo = atributos [ 'codigo' ] || atributos [ 'código' ] ;
141181 const retorno : RespostaOpenApi = { } ;
182+
142183 for ( const [ nomeAtributo , valorAtributo ] of Object . entries ( atributos ) ) {
143184 const nomeOpenApi = decoradoresValidosResposta [ nomeAtributo ] ;
144- if ( nomeOpenApi === 'statusCode' ) {
145- continue ;
146- }
185+ if ( nomeOpenApi === 'statusCode' ) continue ;
147186
148187 if ( nomeOpenApi === 'content' ) {
149188 retorno . content = valorAtributo ;
@@ -158,7 +197,10 @@ export class AutoDocumentador implements AutoDocumentadorInterface {
158197
159198 protected resolverDecorador ( decorador : Decorador ) : any {
160199 if ( ! ( decorador . nome in this . decoradoresValidos ) ) {
161- this . erros . push ( new Error ( `Decorador ${ decorador . nome } não é válido para um método de um controlador.` ) ) ;
200+ this . erros . push ( new Error (
201+ `Decorador ${ decorador . nome } não é válido para um método de um controlador.`
202+ ) ) ;
203+
162204 return null ;
163205 }
164206
@@ -185,24 +227,39 @@ export class AutoDocumentador implements AutoDocumentadorInterface {
185227 declaracoes : Declaracao [ ]
186228 ) : [ string , { [ key in MetodoHttpOpenApi ] ?: RotaOpenApi } ] {
187229 const descritivoControlador : { [ key in MetodoHttpOpenApi ] ?: RotaOpenApi } = { } ;
188- const rotaRelativa = caminhoControlador
189- . replace ( this . diretorioRotas , '' )
190- . replace ( 'inicial.delegua' , '' )
191- . replace ( '.delegua' , '' ) ;
192230
193- // console.log('rotaRelativa', rotaRelativa);
231+ // Remove o prefixo do diretório de rotas e a extensão do arquivo
232+ // para obter o caminho relativo da rota
233+ let rotaRelativa = caminhoControlador . substring (
234+ this . diretorioRotas . length
235+ ) ;
236+
237+ rotaRelativa = rotaRelativa . replace ( / i n i c i a l \. ( d e l e g u a | p i t u ) $ / , '' ) ;
238+ rotaRelativa = rotaRelativa . replace ( / \. ( d e l e g u a | p i t u ) $ / , '' ) ;
239+ rotaRelativa = rotaRelativa . replace ( / \[ ( .+ ?) \] / g, '{$1}' ) ;
194240
195241 for ( const declaracao of declaracoes ) {
196- // Os decoradores contêm a documentação adicional para uma rota.
242+ if ( ! ( declaracao instanceof Expressao ) ) continue ;
243+
244+ const expressao = declaracao . expressao ;
245+
246+ if ( ! ( expressao instanceof Chamada ) ) continue ;
247+
248+ const chamada = expressao ;
197249 const decoradores = declaracao . decoradores ;
198- // Aqui normalmente teremos uma expressão com uma chamada dentro.
199- const chamada = ( declaracao as Expressao ) . expressao as Chamada ;
200- // Tipicamente, a entidade chamada é uma variável com o nome reservado `liquido`.
201- // o método é um Símbolo.
202- // A execução e middlewares ficam em argumentos.
203- const entidadeChamada = chamada . entidadeChamada as AcessoMetodoOuPropriedade ;
204- // const argumentos = chamada.argumentos;
205- // console.log(decoradores, argumentos, entidadeChamada.objeto, entidadeChamada.simbolo);
250+
251+ // Extrai o nome do método (rotaGet, rotaPost, ...) suportando
252+ // AcessoMetodo (Delégua) e AcessoMetodoOuPropriedade (Pituguês)
253+ let nomeMetodo : string | null = null ;
254+ const entidadeChamada = chamada . entidadeChamada ;
255+
256+ if ( entidadeChamada instanceof AcessoMetodo ) {
257+ nomeMetodo = entidadeChamada . nomeMetodo ;
258+ } else if ( entidadeChamada instanceof AcessoMetodoOuPropriedade ) {
259+ nomeMetodo = entidadeChamada . simbolo . lexema ;
260+ }
261+
262+ if ( ! nomeMetodo ) continue ;
206263
207264 let descritivoMetodoRota : RotaOpenApi = { } ;
208265 for ( const decorador of decoradores ) {
@@ -219,7 +276,8 @@ export class AutoDocumentador implements AutoDocumentadorInterface {
219276 }
220277 }
221278
222- const metodoResolvido = entidadeChamada . simbolo . lexema . replace ( 'rota' , '' ) ;
279+ const metodoResolvido = nomeMetodo . replace ( 'rota' , '' ) ;
280+
223281 descritivoControlador [ metodoResolvido . toLowerCase ( ) as MetodoHttpOpenApi ] = descritivoMetodoRota ;
224282 }
225283
0 commit comments