|
| 1 | +import type { RShell } from '../../r-bridge/shell'; |
| 2 | +import type { SupportedQueryTypes } from '../../queries/query'; |
| 3 | +import { PipelineExecutor } from '../../core/pipeline-executor'; |
| 4 | +import { DEFAULT_DATAFLOW_PIPELINE } from '../../core/steps/pipeline/default-pipelines'; |
| 5 | +import { requestFromInput } from '../../r-bridge/retriever'; |
| 6 | +import { getFilePathMd } from './doc-files'; |
| 7 | +import type { SupportedVirtualQueryTypes } from '../../queries/virtual-query/virtual-queries'; |
| 8 | +import { printDfGraphForCode } from './doc-dfg'; |
| 9 | +import { codeBlock } from './doc-code'; |
| 10 | +import { printAsMs } from '../../util/time'; |
| 11 | +import type { FlowrSearchLike } from '../../search/flowr-search-builder'; |
| 12 | +import { runSearch } from '../../search/flowr-search-executor'; |
| 13 | +import { flowrSearchToCode, flowrSearchToMermaid } from '../../search/flowr-search-printer'; |
| 14 | +import { recoverContent } from '../../r-bridge/lang-4.x/ast/model/processing/node-id'; |
| 15 | +import { formatRange } from '../../util/mermaid/dfg'; |
| 16 | + |
| 17 | +export interface ShowSearchOptions { |
| 18 | + readonly showCode?: boolean; |
| 19 | + readonly collapseResult?: boolean; |
| 20 | +} |
| 21 | + |
| 22 | +export async function showSearch(shell: RShell, code: string, search: FlowrSearchLike, { collapseResult = true }: ShowSearchOptions = {}): Promise<string> { |
| 23 | + const now = performance.now(); |
| 24 | + const analysis = await new PipelineExecutor(DEFAULT_DATAFLOW_PIPELINE, { |
| 25 | + shell, |
| 26 | + request: requestFromInput(code) |
| 27 | + }).allRemainingSteps(); |
| 28 | + const result = runSearch(search, analysis); |
| 29 | + const duration = performance.now() - now; |
| 30 | + |
| 31 | + const metaInfo = ` |
| 32 | +The search required _${printAsMs(duration)}_ (including parsing and normalization and the query) within the generation environment. |
| 33 | + `.trim(); |
| 34 | + |
| 35 | + return ` |
| 36 | +
|
| 37 | +${codeBlock('ts', flowrSearchToCode(search))} |
| 38 | +
|
| 39 | +<details style="color:gray"> <summary>Search Visualization</summary> |
| 40 | +
|
| 41 | +${codeBlock('mermaid', flowrSearchToMermaid(search))} |
| 42 | +
|
| 43 | +In the code: |
| 44 | +
|
| 45 | +${codeBlock('r', code)} |
| 46 | +
|
| 47 | +<details style="color:gray"> <summary>JSON Representation</summary> |
| 48 | +
|
| 49 | +${codeBlock('json', JSON.stringify(search, null, 2))} |
| 50 | +
|
| 51 | +</details> |
| 52 | +
|
| 53 | +</details> |
| 54 | +
|
| 55 | +
|
| 56 | +${collapseResult ? ' <details> <summary style="color:gray">Show Results</summary>' : ''} |
| 57 | +
|
| 58 | +The query returns the following vetices (all references to \`x\` in the code): |
| 59 | +${ |
| 60 | + result.map(({ node }) => `<b>${node.info.id} ('${recoverContent(node.info.id, analysis.dataflow.graph)}')</b> at L${formatRange(node.location)}`).join(', ') |
| 61 | +} |
| 62 | +
|
| 63 | +${metaInfo} |
| 64 | +
|
| 65 | +The returned results are highlighted thick and blue within the dataflow graph: |
| 66 | +
|
| 67 | +${await printDfGraphForCode(shell, code, { showCode: false, switchCodeAndGraph: false, mark: new Set(result.map(({ node }) => node.info.id )) } )} |
| 68 | +
|
| 69 | +
|
| 70 | +${collapseResult ? '</details>' : ''} |
| 71 | +
|
| 72 | + `; |
| 73 | + |
| 74 | +} |
| 75 | + |
| 76 | +export interface QueryDocumentation { |
| 77 | + readonly name: string; |
| 78 | + readonly type: 'virtual' | 'active'; |
| 79 | + readonly shortDescription: string; |
| 80 | + readonly functionName: string; |
| 81 | + readonly functionFile: string; |
| 82 | + readonly buildExplanation: (shell: RShell) => Promise<string>; |
| 83 | +} |
| 84 | + |
| 85 | +export const RegisteredQueries = { |
| 86 | + 'active': new Map<string, QueryDocumentation>(), |
| 87 | + 'virtual': new Map<string, QueryDocumentation>() |
| 88 | +}; |
| 89 | + |
| 90 | +export function registerQueryDocumentation(query: SupportedQueryTypes | SupportedVirtualQueryTypes, doc: QueryDocumentation) { |
| 91 | + const map = RegisteredQueries[doc.type]; |
| 92 | + if(map.has(query)) { |
| 93 | + throw new Error(`Query ${query} already registered`); |
| 94 | + } |
| 95 | + map.set(query, doc); |
| 96 | +} |
| 97 | + |
| 98 | +function linkify(name: string) { |
| 99 | + return name.toLowerCase().replace(/ /g, '-'); |
| 100 | +} |
| 101 | + |
| 102 | +export function linkToQueryOfName(id: SupportedQueryTypes | SupportedVirtualQueryTypes) { |
| 103 | + const query = RegisteredQueries.active.get(id) ?? RegisteredQueries.virtual.get(id); |
| 104 | + if(!query) { |
| 105 | + throw new Error(`Query ${id} not found`); |
| 106 | + } |
| 107 | + return `[${query.name}](#${linkify(query.name)})`; |
| 108 | +} |
| 109 | + |
| 110 | +export function tocForQueryType(type: 'active' | 'virtual') { |
| 111 | + const queries = [...RegisteredQueries[type].entries()].sort(([,{ name: a }], [, { name: b }]) => a.localeCompare(b)); |
| 112 | + const result: string[] = []; |
| 113 | + for(const [id, { name, shortDescription }] of queries) { |
| 114 | + result.push(`1. [${name}](#${linkify(name)}) (\`${id}\`):\\\n ${shortDescription}`); |
| 115 | + } |
| 116 | + return result.join('\n'); |
| 117 | +} |
| 118 | + |
| 119 | +async function explainQuery(shell: RShell, { name, functionName, functionFile, buildExplanation }: QueryDocumentation) { |
| 120 | + return ` |
| 121 | +### ${name} |
| 122 | +
|
| 123 | +${await buildExplanation(shell)} |
| 124 | +
|
| 125 | +<details> |
| 126 | +
|
| 127 | +<summary style="color:gray">Implementation Details</summary> |
| 128 | +
|
| 129 | +Responsible for the execution of the ${name} query is \`${functionName}\` in ${getFilePathMd(functionFile)}. |
| 130 | +
|
| 131 | +</details> |
| 132 | +
|
| 133 | +`; |
| 134 | +} |
| 135 | + |
| 136 | +export async function explainQueries(shell: RShell, type: 'active' | 'virtual'): Promise<string> { |
| 137 | + const queries = [...RegisteredQueries[type].entries()].sort(([,{ name: a }], [, { name: b }]) => a.localeCompare(b)); |
| 138 | + const result: string[] = []; |
| 139 | + for(const [,doc] of queries) { |
| 140 | + result.push(await explainQuery(shell, doc)); |
| 141 | + } |
| 142 | + return result.join(`\n${'-'.repeat(5)}\n\n`); |
| 143 | +} |
0 commit comments