@@ -4,13 +4,18 @@ import {
44 readableStreamFromIterable ,
55 SubProcess ,
66 type SubprocessErrorData ,
7+ trace ,
8+ context ,
9+ Context ,
710} from "../../deps.ts" ;
811
912import { templateHtml , makeErrorResponse , HtmlHeaders } from '../../lib/request-handling.ts' ;
1013import { findModuleSlug , resolveModuleUrl } from "../../lib/resolve.ts" ;
1114import { computeGraph , renderGraph } from "./compute.ts" ;
1215
13- export async function * handleRequest ( req : Request , modSlug : string , args : URLSearchParams ) {
16+ const tracer = trace . getTracer ( 'dependencies-of-api' ) ;
17+
18+ export async function handleRequest ( req : Request , modSlug : string , args : URLSearchParams ) {
1419 if ( modSlug == '' ) {
1520 const url = args . get ( 'url' ) ;
1621 if ( ! url ) return ;
@@ -26,7 +31,7 @@ export async function *handleRequest(req: Request, modSlug: string, args: URLSea
2631
2732 const slug = await findModuleSlug ( url ) ;
2833 const location = slug + ( args . toString ( ) ? `?${ args } ` : '' ) ;
29- yield new Response ( `302: ${ location } ` , {
34+ return new Response ( `302: ${ location } ` , {
3035 status : 302 ,
3136 headers : { location } ,
3237 } ) ;
@@ -37,17 +42,13 @@ export async function *handleRequest(req: Request, modSlug: string, args: URLSea
3742
3843 switch ( args . get ( 'format' ) ) {
3944 case 'json' :
40- yield serveBufferedOutput ( req , computeGraph ( modUrl , args ) , 'application/json' ) ;
41- return ;
45+ return await serveBufferedOutput ( req , computeGraph ( modUrl , args ) , 'application/json' ) ;
4246 case 'dot' :
43- yield serveBufferedOutput ( req , computeGraph ( modUrl , args ) , 'text/plain; charset=utf-8' ) ;
44- return ;
47+ return await serveBufferedOutput ( req , computeGraph ( modUrl , args ) , 'text/plain; charset=utf-8' ) ;
4548 case 'svg' :
46- yield serveStreamingOutput ( req , renderGraph ( modUrl , [ "-Tsvg" ] , args ) , 'image/svg+xml' ) ;
47- return ;
49+ return await serveStreamingOutput ( req , renderGraph ( modUrl , [ "-Tsvg" ] , args ) , 'image/svg+xml' ) ;
4850 case null :
49- yield serveHtmlGraphPage ( req , modUrl , modSlug , args ) ;
50- return ;
51+ return await serveHtmlGraphPage ( req , modUrl , modSlug , args ) ;
5152 }
5253}
5354
@@ -75,56 +76,40 @@ async function serveStreamingOutput(req: Request, computation: Promise<SubProces
7576
7677const hideLoadMsg = `<style type="text/css">#graph-waiting { display: none; }</style>` ;
7778
78- async function serveHtmlGraphPage ( req : Request , modUrl : string , modSlug : string , args : URLSearchParams ) {
79- args . set ( 'font' , 'Archivo Narrow' ) ;
80-
81- // Render the basic page first, so we can error more cleanly if that fails
82- let pageHtml = '' ;
79+ async function renderModuleToHtml ( modUrl : string , args : URLSearchParams ) {
8380 try {
84- pageHtml = await templateHtml ( 'feat/dependencies-of/public.html' , {
85- module_slug : entities . encode ( modSlug ) ,
86- module_url : entities . encode ( modUrl ) ,
87- export_prefix : entities . encode ( `${ req . url } ${ req . url . includes ( '?' ) ? '&' : '?' } format=` ) ,
88- } ) ;
89- } catch ( err ) {
90- return makeErrorResponse ( err ) ;
91- }
9281
93- const graphPromise = ( ( args . get ( 'renderer' ) === 'interactive' )
94-
95- ? computeGraph ( modUrl , args , 'dot' )
96- . then ( data => {
97- return `
98- <div id="graph"></div>
99- <script type="text/javascript" src="https://unpkg.com/vis-network@9.0.1/standalone/umd/vis-network.min.js"></script>
100- <script type="text/javascript" src="/interactive-graph.js"></script>
101- <template type="text/plain" id="graphviz_data">\n${ data
102- . replace ( / & / g, '&' )
103- . replace ( / > / g, '>' )
104- . replace ( / < / g, '<' )
105- } </template>
106- <script type="text/javascript">
107- window.CreateModuleGraph(document.getElementById('graphviz_data').innerHTML
108- .replace(/>/g, '>')
109- .replace(/</g, '<')
110- .replace(/&/g, '&'));
111- </script>
112- ` . replace ( / ^ { 10 } / gm, '' ) ;
113- } )
114-
115- : renderGraph ( modUrl , [ "-Tsvg" ] , args )
116- . then ( dotProc => dotProc . captureAllOutput ( ) )
117- . then ( raw => {
118- const fullSvg = new TextDecoder ( ) . decode ( raw ) ;
119- const attrs = [ `id="graph"` ] ;
120- const svgWidth = fullSvg . match ( / v i e w B o x = " (?: ( [ 0 - 9 . - ] + ) ) { 3 } / ) ?. [ 1 ] ;
121- if ( svgWidth ) attrs . push ( `style="max-width: ${ parseInt ( svgWidth ) * 2 } px;"` ) ;
122- return fullSvg
123- . slice ( fullSvg . indexOf ( '<!--' ) )
124- . replace ( / < s v g w i d t h = " [ ^ " ] + " h e i g h t = " [ ^ " ] + " / , '<svg ' + attrs . join ( ' ' ) ) ;
125- } )
126-
127- ) . catch ( err => {
82+ if ( args . get ( 'renderer' ) === 'interactive' ) {
83+ const data = await computeGraph ( modUrl , args , 'dot' ) ;
84+ return `
85+ <div id="graph"></div>
86+ <script type="text/javascript" src="https://unpkg.com/vis-network@9.0.1/standalone/umd/vis-network.min.js"></script>
87+ <script type="text/javascript" src="/interactive-graph.js"></script>
88+ <template type="text/plain" id="graphviz_data">\n${ data
89+ . replace ( / & / g, '&' )
90+ . replace ( / > / g, '>' )
91+ . replace ( / < / g, '<' )
92+ } </template>
93+ <script type="text/javascript">
94+ window.CreateModuleGraph(document.getElementById('graphviz_data').innerHTML
95+ .replace(/>/g, '>')
96+ .replace(/</g, '<')
97+ .replace(/&/g, '&'));
98+ </script>
99+ ` . replace ( / ^ { 8 } / gm, '' ) ;
100+ }
101+
102+ const dotProc = await renderGraph ( modUrl , [ "-Tsvg" ] , args ) ;
103+ const raw = await dotProc . captureAllOutput ( ) ;
104+ const fullSvg = new TextDecoder ( ) . decode ( raw ) ;
105+ const attrs = [ `id="graph"` ] ;
106+ const svgWidth = fullSvg . match ( / v i e w B o x = " (?: ( [ 0 - 9 . - ] + ) ) { 3 } / ) ?. [ 1 ] ;
107+ if ( svgWidth ) attrs . push ( `style="max-width: ${ parseInt ( svgWidth ) * 2 } px;"` ) ;
108+ return fullSvg
109+ . slice ( fullSvg . indexOf ( '<!--' ) )
110+ . replace ( / < s v g w i d t h = " [ ^ " ] + " h e i g h t = " [ ^ " ] + " / , '<svg ' + attrs . join ( ' ' ) ) ;
111+
112+ } catch ( err ) {
128113 if ( err . subproc ) {
129114 const info = err . subproc as SubprocessErrorData ;
130115 return `
@@ -140,7 +125,30 @@ async function serveHtmlGraphPage(req: Request, modUrl: string, modSlug: string,
140125 }
141126 console . error ( 'Graph computation error:' , err . stack ) ;
142127 return `<div id="graph-error">${ entities . encode ( err . stack ) } </div>` ;
143- } ) ;
128+ }
129+ }
130+
131+ async function serveHtmlGraphPage ( req : Request , modUrl : string , modSlug : string , args : URLSearchParams ) {
132+ args . set ( 'font' , 'Archivo Narrow' ) ;
133+
134+ // Render the basic page first, so we can error more cleanly if that fails
135+ let pageHtml = '' ;
136+ try {
137+ pageHtml = await templateHtml ( 'feat/dependencies-of/public.html' , {
138+ module_slug : entities . encode ( modSlug ) ,
139+ module_url : entities . encode ( modUrl ) ,
140+ export_prefix : entities . encode ( `${ req . url } ${ req . url . includes ( '?' ) ? '&' : '?' } format=` ) ,
141+ } ) ;
142+ } catch ( err ) {
143+ return makeErrorResponse ( err ) ;
144+ }
145+
146+ const graphPromise = tracer . startActiveSpan ( 'Compute + Render Graph' , {
147+ attributes : {
148+ 'render.mod_url' : modUrl ,
149+ 'render.params' : args . toString ( ) ,
150+ } ,
151+ } , context . active ( ) , span => renderModuleToHtml ( modUrl , args ) . finally ( ( ) => span . end ( ) ) ) ;
144152
145153 // Return the body in two parts, with a comment in between
146154 return new Response ( readableStreamFromIterable ( ( async function * ( ) {
0 commit comments