UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

1,137 lines 64.1 kB
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WikiQuery = void 0;
const doc_dfg_1 = require("./doc-util/doc-dfg");
const query_1 = require("../queries/query");
const doc_files_1 = require("./doc-util/doc-files");
const doc_query_1 = require("./doc-util/doc-query");
const schema_1 = require("../util/schema");
const ansi_1 = require("../util/text/ansi");
const call_context_query_executor_1 = require("../queries/catalog/call-context-query/call-context-query-executor");
const compound_query_1 = require("../queries/virtual-query/compound-query");
const example_query_code_1 = require("./data/query/example-query-code");
const doc_structure_1 = require("./doc-util/doc-structure");
const doc_code_1 = require("./doc-util/doc-code");
const dataflow_query_executor_1 = require("../queries/catalog/dataflow-query/dataflow-query-executor");
const id_map_query_executor_1 = require("../queries/catalog/id-map-query/id-map-query-executor");
const normalized_ast_query_executor_1 = require("../queries/catalog/normalized-ast-query/normalized-ast-query-executor");
const cluster_query_executor_1 = require("../queries/catalog/cluster-query/cluster-query-executor");
const static_slice_query_executor_1 = require("../queries/catalog/static-slice-query/static-slice-query-executor");
const dependencies_query_executor_1 = require("../queries/catalog/dependencies-query/dependencies-query-executor");
const doc_cli_option_1 = require("./doc-util/doc-cli-option");
const doc_issue_1 = require("./doc-util/doc-issue");
const location_map_query_executor_1 = require("../queries/catalog/location-map-query/location-map-query-executor");
const identify_link_to_last_call_relation_1 = require("../queries/catalog/call-context-query/identify-link-to-last-call-relation");
const config_query_executor_1 = require("../queries/catalog/config-query/config-query-executor");
const search_query_executor_1 = require("../queries/catalog/search-query/search-query-executor");
const flowr_search_builder_1 = require("../search/flowr-search-builder");
const vertex_1 = require("../dataflow/graph/vertex");
const control_flow_query_executor_1 = require("../queries/catalog/control-flow-query/control-flow-query-executor");
const doc_cfg_1 = require("./doc-util/doc-cfg");
const doc_repl_1 = require("./doc-util/doc-repl");
const inspect_higher_order_query_executor_1 = require("../queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor");
const doc_escape_1 = require("./doc-util/doc-escape");
const doc_maker_1 = require("./wiki-mk/doc-maker");
const files_query_executor_1 = require("../queries/catalog/files-query/files-query-executor");
const call_graph_query_executor_1 = require("../queries/catalog/call-graph-query/call-graph-query-executor");
const inspect_recursion_query_executor_1 = require("../queries/catalog/inspect-recursion-query/inspect-recursion-query-executor");
const does_call_query_executor_1 = require("../queries/catalog/does-call-query/does-call-query-executor");
const inspect_exception_query_executor_1 = require("../queries/catalog/inspect-exceptions-query/inspect-exception-query-executor");
const slice_direction_1 = require("../util/slice-direction");
const provenance_query_executor_1 = require("../queries/catalog/provenance-query/provenance-query-executor");
const input_sources_query_executor_1 = require("../queries/catalog/input-sources-query/input-sources-query-executor");
const absint_query_executor_1 = require("../queries/catalog/absint-query/absint-query-executor");
const dice_query_executor_1 = require("../queries/catalog/dice-query/dice-query-executor");
const dataflow_lens_query_executor_1 = require("../queries/catalog/dataflow-lens-query/dataflow-lens-query-executor");
const signature_query_executor_1 = require("../queries/catalog/signature-query/signature-query-executor");
const doc_sigdb_1 = require("./doc-util/doc-sigdb");
const guess_dep_versions_query_executor_1 = require("../queries/catalog/guess-dep-versions-query/guess-dep-versions-query-executor");
(0, doc_query_1.registerQueryDocumentation)('call-context', {
    type: 'active',
    shortDescription: 'Finds all calls in a set of files that matches specified criteria.',
    functionName: call_context_query_executor_1.executeCallContextQueries.name,
    functionFile: '../queries/catalog/call-context-query/call-context-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        return `
Call context queries can be used to identify calls to specific functions that match criteria of your interest.
For now, we support two criteria:

1. **Function Name** (\`callName\`): The function name is specified by a regular expression. This allows you to find all calls to functions that match a specific pattern. Please note, that if you do not use Regex-Anchors, the query will match any function name that contains the given pattern (you can set the \`callNameExact\` property to \`true\` to automatically add the \`^...$\` anchors).
2. **Call Targets**  (\`callTargets\`): This specifies to what the function call targets. For example, you may want to find all calls to a function that is not defined locally.

Besides this, we provide the following ways to automatically categorize and link identified invocations:

1. **Kind**         (\`kind\`): This is a general category that can be used to group calls together. For example, you may want to link all calls to \`plot\` to \`visualize\`.
2. **Subkind**      (\`subkind\`): This is used to uniquely identify the respective call type when grouping the output. For example, you may want to link all calls to \`ggplot\` to \`plot\`.
3. **Linked Calls** (\`linkTo\`): This links the current call to the last/nested/.. call of the given kind. This way, you can link a call like \`points\` to the latest graphics plot etc.
4. **Aliases**      (\`includeAliases\`): Consider a case like \`f <- function_of_interest\`, do you want calls to \`f\` to be included in the results? There is probably no need to combine this with a global call target!

It's also possible to filter the results based on the following properties:

1. **File** (\`fileFilter\`): This allows you to filter the results based on the file in which the call is located. This can be useful if you are only interested in calls in, e.g., specific folders.
   The \`fileFilter\` property is an object made up of two properties:
     - **Filter** (\`filter\`): A regular expression that a node's file attribute must match to be considered.
     - **Include Undefined Files** (\`includeUndefinedFiles\`): If \`fileFilter\` is set, but a node's file attribute is not present, should we include it in the results? Defaults to \`true\`.
2. **Ignore Parameter Values** (\`ignoreParameterValues\`): Should we ignore default values for parameters in the results?

Re-using the example code from above, the following query attaches all calls to \`mean\` to the kind \`visualize\` and the subkind \`text\`,
all calls that start with \`read_\` to the kind \`input\` but only if they are not locally overwritten, and the subkind \`csv-file\`, and links all calls to \`points\` to the last call to \`plot\`:

${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode, [
            { type: 'call-context', callName: '^mean$', kind: 'visualize', subkind: 'text' },
            {
                type: 'call-context',
                callName: '^read_',
                kind: 'input',
                subkind: 'csv-file',
                callTargets: identify_link_to_last_call_relation_1.CallTargets.OnlyGlobal
            },
            {
                type: 'call-context',
                callName: '^points$',
                kind: 'visualize',
                subkind: 'plot',
                linkTo: { type: 'link-to-last-call', callName: '^plot$' }
            }
        ], { showCode: false, ctx })}

As you can see, all kinds and subkinds with the same name are grouped together.
Yet, re-stating common arguments and kinds may be cumbersome (although you can already use clever regex patterns).
See the ${(0, doc_query_1.linkToQueryOfName)('compound')} for a way to structure your queries more compactly if you think it gets too verbose. 

${await (async () => {
            const code = `
foo <- my_test_function
foo()
if(u) bar <- foo
bar()
my_test_function()
`.trim();
            return (0, doc_structure_1.details)('Alias Example', `Consider the following code: ${(0, doc_code_1.codeBlock)('r', code)}\nNow let's say we want to query _all_ uses of the \`my_test_function\`:` + await (0, doc_query_1.showQuery)(shell, code, [
                { type: 'call-context', callName: '^my_test_function', includeAliases: true }
            ], { showCode: false, ctx }));
        })()}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('dataflow', {
    type: 'active',
    shortDescription: 'Returns the dataflow graph of the given code.',
    functionName: dataflow_query_executor_1.executeDataflowQuery.name,
    functionFile: '../queries/catalog/dataflow-query/dataflow-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x + 1';
        return `
Maybe you want to handle only the result of the query execution, or you just need the ${ctx.linkPage('wiki/Dataflow Graph', 'dataflow graph')} again.
This query type does exactly that!

Using the example code \`${exampleCode}\`, the following query returns the dataflow graph of the code:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'dataflow'
            }], { showCode: true, collapseQuery: true, ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('call-graph', {
    type: 'active',
    shortDescription: 'Returns the call graph of the given code.',
    functionName: call_graph_query_executor_1.executeCallGraphQuery.name,
    functionFile: '../queries/catalog/call-graph-query/call-graph-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x + 1';
        return `
This query calculates and returns the ${ctx.linkPage('wiki/Dataflow Graph', 'call graph', 'perspectives-cg')} of the given code.

Using the example code \`${exampleCode}\`, the following query returns the dataflow graph of the code:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'call-graph'
            }], { showCode: true, collapseQuery: true, ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('does-call', {
    type: 'active',
    shortDescription: 'Checks whether a function calls another function matching given constraints.',
    functionName: does_call_query_executor_1.executeDoesCallQuery.name,
    functionFile: '../queries/catalog/does-call-query/does-call-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'f <- function(x) { eval(x) };\nf("1 + 1")';
        return `
This query checks whether a function calls another function matching given constraints.

Using the example code:
${(0, doc_code_1.codeBlock)('r', exampleCode)}
the following query checks whether the call to \`f\` calls \`eval\`:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'does-call',
                queryId: 'calls-eval',
                call: '2@f',
                calls: { type: 'name', name: 'eval', nameExact: true }
            }], { showCode: true, collapseQuery: false, shorthand: '(2@f:"eval")', ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('files', {
    type: 'active',
    shortDescription: 'Returns the files matching the given criteria.',
    functionName: files_query_executor_1.executeFileQuery.name,
    functionFile: '../queries/catalog/files-query/files-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        return `
This query returns the files that match the given criteria.
${await (0, doc_query_1.showQuery)(shell, '', [{
                type: 'files'
            }], { showCode: true, collapseQuery: true, ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('project', {
    type: 'active',
    shortDescription: 'Returns information about the analyzed project',
    functionName: dataflow_query_executor_1.executeDataflowQuery.name,
    functionFile: '../queries/catalog/project-query/project-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x + 1';
        return `
This query returns the information about the analyzed project.
If present, it will incorporate plugins to, e.g., extract author and license information from R package DESCRIPTION files.

${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'project'
            }], { showCode: true, collapseQuery: true, ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('normalized-ast', {
    type: 'active',
    shortDescription: 'Returns the normalized AST of the given code.',
    functionName: normalized_ast_query_executor_1.executeNormalizedAstQuery.name,
    functionFile: '../queries/catalog/normalized-ast-query/normalized-ast-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x + 1';
        return `
Maybe you want to handle only the result of the query execution, or you just need the ${ctx.linkPage('wiki/Normalized AST', 'normalized AST')} again.
This query type does exactly that!

Using the example code \`${exampleCode}\`, the following query returns the normalized AST of the code:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'normalized-ast'
            }], { showCode: true, collapseQuery: true, ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('dataflow-cluster', {
    type: 'active',
    shortDescription: 'Calculates and returns all the clusters present in the dataflow graph.',
    functionName: cluster_query_executor_1.executeDataflowClusterQuery.name,
    functionFile: '../queries/catalog/cluster-query/cluster-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleA = 'x <- 1; x';
        const exampleB = 'x <- 1; y';
        return `
This query automatically calculates clusters in flowR's dataflow graph 
and returns a list of all clusters found. 
Clusters are to be interpreted as literal clusters on the graph traversing
edges in both directions. From this perspective, 
the code \`${exampleA}\` has one cluster (given that all code is related), 
while the code \`${exampleB}\` has two clusters (given that the \`y\` has no relation to the previous definition).

${(0, doc_structure_1.details)('Example <code>' + exampleA + '</code>', await (0, doc_query_1.showQuery)(shell, exampleA, [{ type: 'dataflow-cluster' }], { showCode: false, ctx }))}
${(0, doc_structure_1.details)('Example <code>' + exampleB + '</code>', await (0, doc_query_1.showQuery)(shell, exampleB, [{ type: 'dataflow-cluster' }], { showCode: false, ctx }))}

Using the example code from above, the following query returns all clusters:
${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode, [{
                type: 'dataflow-cluster'
            }], { showCode: false, collapseQuery: true, ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('resolve-value', {
    type: 'active',
    shortDescription: 'Provides access to flowR\'s value tracking (which is configurable)',
    functionName: search_query_executor_1.executeSearch.name,
    functionFile: '../queries/catalog/resolve-value-query/resolve-value-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x <- 1\ny <-2\nprint(x)\nprint(y)';
        const criteria = ['3@x', '4@y'];
        return `
With this query you can use flowR's value-tracking capabilities to resolve identifiers to all potential values they may have at runtime (if possible).
The extent to which flowR traces values (e.g., built-ins vs. constants) can be configured in flowR's Configuration file (see the ${ctx.linkPage('wiki/Interface', 'Interface')} wiki page for more information).

Using the example code \`${exampleCode}\` (with newlines), the following query returns all values of \`x\` in the code:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'resolve-value',
                criteria: criteria
            }], { showCode: true, shorthand: (0, doc_query_1.sliceQueryShorthand)(criteria, (0, doc_escape_1.escapeNewline)(exampleCode)), ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('inspect-higher-order', {
    type: 'active',
    shortDescription: 'Determine whether functions are higher-order functions',
    functionName: inspect_higher_order_query_executor_1.executeHigherOrderQuery.name,
    functionFile: '../queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'f <- function() function(x) x; f()';
        return `
With this query you can identify which functions in the code are higher-order functions, i.e., either take a function as an argument or return a function.
Please note, that functions that are just identities (e.g., \`function(x) x\`) are not considered higher-order if they do not take a function as an argument.

Using the example code \`${exampleCode}\` the following query returns the information for all identified function definitions whether they are higher-order functions:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'inspect-higher-order',
            }], { showCode: true, collapseQuery: true, ctx })}

This query also supports a slicing criterion based query mode that only returns information for functions matching the given criteria:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'inspect-higher-order',
                filter: ['1@function']
            }], { showCode: false, shorthand: (0, doc_query_1.sliceQueryShorthand)(['1@function'], (0, doc_escape_1.escapeNewline)(exampleCode)), ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('inspect-recursion', {
    type: 'active',
    shortDescription: 'Determine whether functions are recursive',
    functionName: inspect_recursion_query_executor_1.executeRecursionQuery.name,
    functionFile: '../queries/catalog/inspect-recursion-query/inspect-recursion-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'fact <- function(n) { if(n <= 1) 1 else n * fact(n - 1) }';
        return `
With this query you can identify which functions in the code are recursive.
Please note, that functions that *may* be recursive due to indirect calls are also considered recursive.

Using the example code \`${exampleCode}\` the following query returns the information for all identified function definitions whether they are recursive:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'inspect-recursion',
            }], { showCode: true, collapseQuery: true, ctx })}

This query also supports a slicing criterion based query mode that only returns information for functions matching the given criteria:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'inspect-recursion',
                filter: ['1@function']
            }], { showCode: true, shorthand: (0, doc_query_1.sliceQueryShorthand)(['1@function'], (0, doc_escape_1.escapeNewline)(exampleCode)), ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('inspect-exception', {
    type: 'active',
    shortDescription: 'Determine whether functions throw exceptions (known to flowR)',
    functionName: inspect_exception_query_executor_1.executeExceptionQuery.name,
    functionFile: '../queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = `mayFail <- function(x) {
  if(x < 0) stop("Negative value!")
  else sqrt(x)
}
safeFail <- function(x) {
  tryCatch(
    mayFail(x),
    error = function(e) { NA }
  )
}`;
        return `
With this query you can identify which functions in the code throw exceptions (known to flowR).

Using the following example code:
${(0, doc_code_1.codeBlock)('r', exampleCode)}
the following query returns the information for all identified function definitions whether they throw exceptions:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'inspect-exception',
            }], { showCode: true, collapseQuery: true, ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('origin', {
    type: 'active',
    shortDescription: 'Retrieve the origin of a variable, function call, ...',
    functionName: search_query_executor_1.executeSearch.name,
    functionFile: '../queries/catalog/origin-query/origin-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x <- 1\nprint(x)';
        const criterion = '2@x';
        return `
With this query you can use flowR's origin tracking to find out the read origins of a variable,
the functions called by a call, and more.

Using the example code \`${exampleCode}\` (with the \`print(x)\` in the second line), the following query returns the origins of \`x\` in the code:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'origin',
                criterion: criterion
            }], { showCode: true, shorthand: (0, doc_query_1.sliceQueryShorthand)([criterion], (0, doc_escape_1.escapeNewline)(exampleCode)), ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('search', {
    type: 'active',
    shortDescription: 'Provides access to flowR\'s search API',
    functionName: search_query_executor_1.executeSearch.name,
    functionFile: '../queries/catalog/search-query/search-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x + 1';
        return `
With this query you can use the ${ctx.linkPage('wiki/Search API', 'Search API')} to conduct searches on the flowR analysis result.

Using the example code \`${exampleCode}\`, the following query returns all uses of 'x' in the code:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'search',
                search: flowr_search_builder_1.Q.var('x').filter(vertex_1.VertexType.Use).build()
            }], { showCode: true, collapseQuery: false, ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('happens-before', {
    type: 'active',
    shortDescription: 'Check whether one normalized AST node happens before another in the CFG.',
    functionName: search_query_executor_1.executeSearch.name,
    functionFile: '../queries/catalog/happens-before-query/happens-before-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x <- 1\ny <- 2';
        return `
With this query you can analyze the control flow graph:

Using the example code:

${(0, doc_code_1.codeBlock)('r', exampleCode)}

the following query returns that the first assignment happens always before the other:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'happens-before',
                a: '1@x',
                b: '2@y'
            }], { showCode: true, collapseQuery: false, ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('id-map', {
    type: 'active',
    shortDescription: 'Returns the id-map of the normalized AST of the given code.',
    functionName: id_map_query_executor_1.executeIdMapQuery.name,
    functionFile: '../queries/catalog/id-map-query/id-map-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x + 1';
        return `
This query provides access to all nodes in the ${ctx.linkPage('wiki/Normalized AST', 'normalized AST')} as a mapping from their id to the node itself.

Using the example code \`${exampleCode}\`, the following query returns all nodes from the code:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'id-map'
            }], { showCode: true, collapseQuery: true, ctx })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('config', {
    type: 'active',
    shortDescription: 'Returns the current configuration of flowR.',
    functionName: config_query_executor_1.executeConfigQuery.name,
    functionFile: '../queries/catalog/config-query/config-query-format.ts',
    buildExplanation: async (shell, ctx) => {
        return `
This query provides access to the current configuration of the flowR instance. See the ${ctx.linkPage('wiki/Interface', 'Interface')} wiki page for more information on what the configuration represents.
Additionally, you can use this query to update the configuration of flowR on-the-fly (please do not rely on this mechanism it is mostly of interest for demonstrations).
${await (0, doc_query_1.showQuery)(shell, '', [{
                type: 'config',
                update: {
                    ignoreSourceCalls: true
                }
            }], { showCode: false, collapseQuery: true, collapseResult: true, ctx })}

Please note that, in the REPL, a special syntax starting with \`+\` (which should be autocompleted) can be used to update the configuration on the fly:

${await (0, doc_repl_1.documentReplSession)(shell, [
            {
                command: ':query @config +solver.slicer.threshold=10000',
                description: 'Set the slicing threshold to 10,000.'
            }
        ])}

In the REPL you can also read a single option by its \`.\`-separated path, or several at once with a glob&mdash;\`*\` covers
one path segment, \`**\` any number. This only reads: setting a value still names exactly one key.

${await (0, doc_repl_1.documentReplSession)(shell, [
            {
                command: ':query @config **.enabled',
                description: 'Read every `enabled` option, wherever it sits in the configuration.'
            },
            {
                command: ':query @config solver.*',
                description: 'Read the direct children of `solver` (use `solver.**` for the whole subtree).'
            }
        ])}

One of the most useful options to change on-the-fly are probably those under \`repl\`. For example, setting ${ctx.linkConfig('repl.quickStats', true)}
enables quick statistics after each REPL command. Likewise, ${ctx.linkConfig('repl.dfProcessorHeat', true)} enables the dataflow processor heatmap after each REPL command.
`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('absint', {
    type: 'active',
    shortDescription: 'Returns the abstract values inferred for every expression or at specific locations.',
    functionName: absint_query_executor_1.executeAbsintQuery.name,
    functionFile: '../queries/catalog/absint-query/absint-query-format.ts',
    buildExplanation: async (shell, ctx) => {
        const criteria = ['1@df', '1@data.frame'];
        const inference = 'df-shape';
        const exampleCode = 'df <- data.frame(id = 1:3) |>\n  filter(df, FALSE)';
        return `
This query infers all shapes of dataframes within the code using abstract interpretaion. For example, you can use:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'absint',
                inference: inference
            }], { showCode: true, collapseQuery: true, ctx })}

The query optionally also accepts slice criteria to narrow the results to specific nodes. For example:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'absint',
                inference: inference,
                criteria: criteria
            }], { showCode: true, collapseQuery: true, shorthand: (0, doc_query_1.sliceQueryShorthand)(criteria, (0, doc_escape_1.escapeNewline)(exampleCode)), ctx })}
`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('compound', {
    name: 'Compound Query',
    type: 'virtual',
    shortDescription: 'Combines multiple queries of the same type into one, specifying common arguments.',
    functionName: compound_query_1.executeCompoundQueries.name,
    functionFile: '../queries/virtual-query/compound-query.ts',
    buildExplanation: async (shell, ctx) => {
        return `
A compound query comes in use, whenever we want to state multiple queries of the same type with a set of common arguments.
It offers the following properties of interest:

1. **Query** (\`query\`): the type of the query that is to be combined.
2. **Common Arguments** (\`commonArguments\`): The arguments that are to be used as defaults for all queries (i.e., any argument the query may have).
3. **Arguments** (\`arguments\`): The other arguments for the individual queries that are to be combined.

For example, consider the following compound query that combines two call-context queries for \`mean\` and \`print\`, both of which are to be
assigned to the kind \`visualize\` and the subkind \`text\` (using the example code from above):

${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode, [{
                type: 'compound',
                query: 'call-context',
                commonArguments: { kind: 'visualize', subkind: 'text' },
                arguments: [
                    { callName: '^mean$' },
                    { callName: '^print$' }
                ]
            }], { showCode: false, ctx })}

Of course, in this specific scenario, the following query would be equivalent:

${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode, [
            { type: 'call-context', callName: '^(mean|print)$', kind: 'visualize', subkind: 'text' }
        ], { showCode: false, collapseResult: true, ctx })}

However, compound queries become more useful whenever common arguments can not be expressed as a union in one of their properties.
Additionally, you can still overwrite default arguments.
In the following, we (by default) want all calls to not resolve to a local definition, except for those to \`print\` for which we explicitly
want to resolve to a local definition:

${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode, [{
                type: 'compound',
                query: 'call-context',
                commonArguments: { kind: 'visualize', subkind: 'text', callTargets: identify_link_to_last_call_relation_1.CallTargets.OnlyGlobal },
                arguments: [
                    { callName: '^mean$' },
                    { callName: '^print$', callTargets: identify_link_to_last_call_relation_1.CallTargets.OnlyLocal }
                ]
            }], { showCode: false, ctx })}

Now, the results no longer contain calls to \`plot\` that are not defined locally.

		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('static-slice', {
    type: 'active',
    shortDescription: 'Slice the dataflow graph reducing the code to just the parts relevant for the given criteria (backward and forward).',
    functionName: static_slice_query_executor_1.executeStaticSliceQuery.name,
    functionFile: '../queries/catalog/static-slice-query/static-slice-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x <- 1\ny <- 2\nz <- 3\nx';
        const criteria = ['3@z', '4@x'];
        const sourceExample = 'source("library.R")\nprint(greeting)';
        const sourceCriteria = ['2@print'];
        return `
To slice, _flowR_ needs one thing from you: a variable or a list of variables (function calls are supported to, referring to the anonymous
return of the call) that you want to slice the dataflow graph for (additionally, you have to tell flowR if you want to have a forward slice).
Given this, the backward slice is essentially the subpart of the program that may influence the value of the variables you are interested in.
To specify a variable of interest, you have to present flowR with a [slicing criterion](${doc_files_1.FlowrWikiBaseRef}/Terminology#slicing-criterion) (or, respectively, an array of them).

To exemplify the capabilities, consider the following code:
${(0, doc_code_1.codeBlock)('r', exampleCode)}
If you are interested in the parts required for the use of \`x\` in the last line and \`z\`, you can use the following query:

${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'static-slice',
                criteria: criteria
            }], { showCode: false, shorthand: (0, doc_query_1.sliceQueryShorthand)(criteria, (0, doc_escape_1.escapeNewline)(exampleCode)), ctx })}

In general, you may be uninterested in seeing the reconstructed version and want to save some computation time, for this,
you can use the \`noReconstruction\` flag.

${(0, doc_structure_1.details)('No Reconstruction Example', await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'static-slice',
                criteria: ['4@x'],
                noReconstruction: true
            }], { showCode: false, ctx }))}

Likewise, if you want the forward slice for the first use of \`x\`, you can do it like this:

${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'static-slice',
                criteria: ['1@x'],
                direction: slice_direction_1.SliceDirection.Forward
            }], { showCode: false, shorthand: (0, doc_query_1.sliceQueryShorthand)(['1@x'], (0, doc_escape_1.escapeNewline)(exampleCode), true), ctx })}

If your program pulls in other files with \`source(...)\`, the \`inlineSources\` flag splices the reconstruction
of each resolvable sourced file into the place of its \`source()\` call, so the slice becomes a single
self-contained R text (cyclic or unresolvable \`source()\` calls are kept verbatim and reported via
\`reconstruct.inlineWarnings\`). With the ${(0, doc_cli_option_1.getReplCommand)('query')} REPL command you append an \`i\` to the
criteria (and may combine it with the forward \`f\` as \`fi\`), for example (with a faked \`library.R\` providing \`greeting\`):
${await (0, doc_query_1.showQuery)(shell, sourceExample, [{
                type: 'static-slice',
                criteria: sourceCriteria,
                inlineSources: true
            }], {
            showCode: false,
            shorthand: (0, doc_query_1.sliceQueryShorthand)(sourceCriteria, (0, doc_escape_1.escapeNewline)(sourceExample), false, true),
            ctx,
            files: [{ name: 'library.R', content: 'greeting <- "hello"\nunused <- 123' }]
        })}

You can disable ${ctx.linkPage('wiki/Interface', 'magic comments', 'slice-magic-comments')} using the \`noMagicComments\` flag.
This query replaces the old ${ctx.linkPage('wiki/Interface', '`request-slice`', 'message-request-slice')} message.
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('provenance', {
    type: 'active',
    shortDescription: 'Calculate the provenance of a given variable, optionally restricted to its enveloping fdef',
    functionName: provenance_query_executor_1.executeProvenanceQuery.name,
    functionFile: '../queries/catalog/provenance-query/provenance-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x <- 1\ny <- 2\nz <- 3\nx';
        const criterion = '4@x';
        return `
Given a [slicing criterion](${doc_files_1.FlowrWikiBaseRef}/Terminology#slicing-criterion), flowR will return the provenance
of the given program element (i.e., all related vertices in a non-interprocedural and non-context sensitive backward slice).

To exemplify the capabilities, consider the following code:
${(0, doc_code_1.codeBlock)('r', exampleCode)}
If you are interested in the provenance of the \`x\` in the last line you can use:

${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'provenance',
                criterion
            }], { showCode: false, shorthand: (0, doc_query_1.sliceQueryShorthand)([criterion], (0, doc_escape_1.escapeNewline)(exampleCode)), ctx })}
`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('input-sources', {
    type: 'active',
    shortDescription: 'Classify the input sources of function calls',
    functionName: input_sources_query_executor_1.executeInputSourcesQuery.name,
    functionFile: '../queries/catalog/input-sources-query/input-sources-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = `
f <- function(x) {
	x <- x * 2
	print(x)
}`.trim();
        const criterion = '3@print';
        const shinyCode = `
server <- function(input, output, session) {
	system(paste("convert", input$file))
}`.trim();
        const shinyCriterion = '2@system';
        return `
Given a [slicing criterion](${doc_files_1.FlowrWikiBaseRef}/Terminology#slicing-criterion) to
something like a function call, flowR classifies the types of all input sources (e.g., arguments).

To exemplify the query, consider the following code:
${(0, doc_code_1.codeBlock)('r', exampleCode)}
If you are interested in the input-sources of the \`print\` call, you can use:

${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'input-sources',
                criterion
            }], { showCode: false, shorthand: (0, doc_query_1.sliceQueryShorthand)([criterion], (0, doc_escape_1.escapeNewline)(exampleCode)), ctx })}

Some objects are handed to the code by a framework rather than defined in it, like the \`input\` of a shiny
server function. The ${ctx.link('InputClassifierConfig::linkedObjects')} configuration lists them, so that reads
of such an object (and of its fields) classify as user input instead of stopping at a ${ctx.link('InputType::Parameter')}:
${(0, doc_code_1.codeBlock)('r', shinyCode)}

${await (0, doc_query_1.showQuery)(shell, shinyCode, [{
                type: 'input-sources',
                criterion: shinyCriterion
            }], { showCode: false, shorthand: (0, doc_query_1.sliceQueryShorthand)([shinyCriterion], (0, doc_escape_1.escapeNewline)(shinyCode)), ctx })}

Every ${ctx.link('LinkedInputObject')} names the object, the ${ctx.link('InputType')} to use for it, and optionally
the parameters the binding function has to declare as well (${ctx.link('LinkedInputObject::withParams')}) - shiny's
\`input\` only counts as such if the function also takes an \`output\`, so that an ordinary function with a
parameter named \`input\` is left alone. Where the framework is handed the function instead of the code naming it,
a ${ctx.link('LinkedInputEntryPoint')} is exact: it says which object goes to which parameter *by position*, just
like R does, so \`shinyApp(ui, function(i, o, s))\` works no matter what those parameters are called.
With ${ctx.link('LinkedInputObject::declaredBy')} a read even links back to its definition - the \`textInput("n", …)\`
behind an \`input$n\` shows up as ${ctx.link('InputSource::declaredAt')}.

You do not have to pass any of this per query: the ${ctx.linkConfig('inputSources', true)} section of flowR's
${ctx.linkPage('wiki/Interface', 'configuration file')} carries the same shape and is *added* to what flowR already
knows, so your framework joins shiny instead of replacing it (and \`specializeConfig\` can scope it to one
${ctx.link('ProjectKind')}). Functions may be written as plain \`fn\` or namespaced \`pkg::fn\` strings; a bare call
only counts as the namespaced one while that package is attached, exactly as R would resolve it.

${(0, doc_code_1.codeBlock)('json', JSON.stringify({ inputSources: {
                user: ['myframework::read_form'],
                linkedObjects: [{ name: 'ctx', type: 'user', declaredBy: { calls: ['myframework::field'], argName: 'id', argIdx: 0 } }],
                linkedEntryPoints: [{ call: 'myframework::serve', argName: 'handler', argIdx: 0, params: ['ctx', null] }]
            } }, undefined, 2))}
`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('dependencies', {
    type: 'active',
    shortDescription: 'Returns all direct dependencies (in- and outputs) of a given R script',
    functionName: dependencies_query_executor_1.executeDependenciesQuery.name,
    functionFile: '../queries/catalog/dependencies-query/dependencies-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'library(x)';
        const longerCode = `
source("sample.R")
foo <- loadNamespace("bar")

data <- read.csv("data.csv")

#' @importFrom ggplot2 ggplot geom_point aes
ggplot(data, aes(x=x, y=y)) + geom_point()

better::write.csv(data, "data2.csv")
print("hello world!")
		`;
        return `
This query extracts all dependencies from an R script, using a combination of a ${(0, doc_query_1.linkToQueryOfName)('call-context')}
and more advanced tracking in the ${ctx.linkPage('wiki/Dataflow Graph', 'Dataflow Graph')}.
Loaded libraries are resolved against the ${ctx.linkPage('wiki/Signature Database', 'signature database')}.

In other words, if you have a script simply reading: \`${exampleCode}\`, the following query returns the loaded library:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'dependencies'
            }], { showCode: false, collapseQuery: true, ctx })}

Of course, this works for more complicated scripts too. The query offers information on the loaded _libraries_, _sourced_ files, data which is _read_ and data which is _written_.
For example, consider the following script:
${(0, doc_code_1.codeBlock)('r', longerCode)}
The following query returns the dependencies of the script.
${await (0, doc_query_1.showQuery)(shell, longerCode, [{
                type: 'dependencies'
            }], { showCode: false, collapseQuery: true, collapseResult: true, ctx })}

Currently, the dependency extraction may fail as it is essentially a set of heuristics guessing the dependencies.
We welcome any feedback on this (consider opening a [new issue](${doc_issue_1.NewIssueUrl})).

In the meantime we offer several properties to overwrite the default behavior (e.g., function names that should be collected)

${await (0, doc_query_1.showQuery)(shell, longerCode, [{
                type: 'dependencies',
                ignoreDefaultFunctions: true,
                enabledCategories: ['library'],
                libraryFunctions: [{ package: 'base', name: 'print', argIdx: 0, argName: 'library', resolveValue: true }],
            }], { showCode: false, collapseQuery: false, collapseResult: true, ctx })}

Here, \`resolveValue\` tells the dependency query to resolve the value of this argument in case it is not a constant.
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('linter', {
    type: 'active',
    shortDescription: 'Lints a given R script for common issues.',
    functionName: dependencies_query_executor_1.executeDependenciesQuery.name,
    functionFile: '../queries/catalog/linter-query/linter-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'read.csv("i_do_not_exist.csv")';
        return `
This query lints a given R script for common issues, such as missing files, unused variables, and more.

In other words, if you have a script simply reading: \`${exampleCode}\`, the following query returns all smells detected:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'linter'
            }], { showCode: false, collapseQuery: true, ctx })}

You can also configure which rules to apply and what settings to use for these rules:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'linter',
                rules: ['file-path-validity'],
            }], {
            showCode: false,
            collapseQuery: true,
            shorthand: `rules:file-path-validity "${exampleCode}"`,
            ctx
        })}

We welcome any feedback and suggestions for new rules on this (consider opening a [new issue](${doc_issue_1.NewIssueUrl})).
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('control-flow', {
    type: 'active',
    shortDescription: 'Provides the control-flow of the program.',
    functionName: control_flow_query_executor_1.executeControlFlowQuery.name,
    functionFile: '../queries/catalog/control-flow-query/control-flow-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'if(TRUE) 1 else 2';
        return `
This control-flow query provides you access to the control flow graph.

In other words, if you have a script simply reading: \`${exampleCode}\`, the following query returns the CFG:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'control-flow'
            }], { showCode: false, collapseQuery: true, collapseResult: true, ctx })}

You can also overwrite the simplification passes to tune the perspective. for example, if you want to have basic blocks:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'control-flow',
                config: {
                    simplificationPasses: ['unique-cf-sets', 'to-basic-blocks']
                }
            }], { showCode: false, collapseResult: true, ctx })}

this produces: 

${await (0, doc_cfg_1.printCfgCode)(shell, exampleCode, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], ctx })}


If, on the other hand, you want to prune dead code edges:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'control-flow',
                config: {
                    simplificationPasses: ['unique-cf-sets', 'analyze-dead-code']
                }
            }], { showCode: false, collapseResult: true, ctx })}

this produces:

${await (0, doc_cfg_1.printCfgCode)(shell, exampleCode, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['analyze-dead-code'], ctx })}


Or, completely remove dead code:
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'control-flow',
                config: {
                    simplificationPasses: ['unique-cf-sets', 'analyze-dead-code', 'remove-dead-code']
                }
            }], { showCode: false, collapseResult: true, ctx })}

this produces:

${await (0, doc_cfg_1.printCfgCode)(shell, exampleCode, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['analyze-dead-code', 'remove-dead-code'], ctx })}

		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('location-map', {
    type: 'active',
    shortDescription: 'Returns a simple mapping of ids to their location in the source file',
    functionName: location_map_query_executor_1.executeLocationMapQuery.name,
    functionFile: '../queries/catalog/location-map-query/location-map-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x + 1\nx * 2';
        const criteria = ['1@x', '2@x'];
        return `
A query like the ${(0, doc_query_1.linkToQueryOfName)('id-map')} query can return a huge result, especially for larger scripts.
If you are not interested in all of the information contained within the full map, you can use the location map query to get a simple mapping of ids to their location in the source file.   

Consider you have the following code:

${(0, doc_code_1.codeBlock)('r', exampleCode)}

The following query then gives you the aforementioned mapping:

${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'location-map'
            }], { showCode: false, collapseQuery: true, ctx })}

The query also accepts a list of slice criteria to filter the results to only include the locations of specific nodes. For example:

${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'location-map',
                ids: criteria
            }], { showCode: false, collapseQuery: true, shorthand: (0, doc_query_1.sliceQueryShorthand)(criteria, (0, doc_escape_1.escapeNewline)(exampleCode)), ctx })}

All locations are given as a ${ctx.link('SourceRange')} paired with the file id in the format \`[file-id, [start-line, start-column, end-line, end-column]]\`.

		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('dice', {
    type: 'active',
    shortDescription: 'Reduces the code to the parts that carry information from a given start point to a given end point.',
    functionName: dice_query_executor_1.executeDiceQuery.name,
    functionFile: '../queries/catalog/dice-query/dice-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'x <- 1\ny <- 2\nz <- x + y\nw <- z * 2\nprint(z)';
        return `
While the ${(0, doc_query_1.linkToQueryOfName)('static-slice')} answers "what affects this point?" (or "what does this point affect?"),
a _dice_ answers the two-sided question: **which parts of the program carry information from A to B?**
It is the intersection of a forward slice seeded at \`from\` and a backward slice seeded at \`to\`,
so only the code that lies on some dependency path between the two criteria survives.

Both \`from\` and \`to\` are arrays of [slicing criteria](${doc_files_1.FlowrWikiBaseRef}/Terminology#slicing-criterion), just like for the ${(0, doc_query_1.linkToQueryOfName)('static-slice')}.
Unlike that query, there is no \`direction\` property: the direction is already fixed by the \`from\`&rarr;\`to\` pairing.

Consider the following code:
${(0, doc_code_1.codeBlock)('r', exampleCode)}

Asking what connects the definition of \`x\` to the definition of \`z\` drops \`y <- 2\` (it never depends on \`x\`)
as well as \`w <- z * 2\` and \`print(z)\` (they are not on a path _into_ the \`to\` criterion):

${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'dice',
                from: ['1@x'],
                to: ['3@z']
            }], { showCode: false, shorthand: `(1@x->3@z) "${(0, doc_escape_1.escapeNewline)(exampleCode)}"`, ctx })}

Beyond \`from\` and \`to\`, the dice query understands the same options as the ${(0, doc_query_1.linkToQueryOfName)('static-slice')}
(\`noReconstruction\`, \`noMagicComments\`, \`inlineSources\`, \`inlineFull\`, and \`includeCallees\`), as both share the
\`SliceQueryOptions\` of ${(0, doc_files_1.getFilePathMd)('../queries/catalog/slice-query-options.ts')}.

${(0, doc_structure_1.details)('Multiple Criteria per Side', 'Each side accepts several criteria, which are seeded together:' + await (0, doc_query_1.showQuery)(shell, exampleCode, [{
                type: 'dice',
                from: ['1@x', '2@y'],
                to: ['5@print']
            }], { showCode: false, ctx }))}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('dataflow-lens', {
    type: 'active',
    shortDescription: 'Returns a simplified view on the dataflow graph, reduced to definitions, uses, and calls.',
    functionName: dataflow_lens_query_executor_1.executeDataflowLensQuery.name,
    functionFile: '../queries/catalog/dataflow-lens-query/dataflow-lens-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'f <- function(a) a + 1\nx <- 1\ny <- f(x)\nprint(y)';
        return `
The ${(0, doc_query_1.linkToQueryOfName)('dataflow')} hands you the complete dataflow graph, which is precise but quickly grows too large to read.
The dataflow lens returns a _reduced_ view of that same graph, keeping only what is usually interesting when looking at it by hand:

* only vertices tagged as a use, a variable definition, a function definition, or a function call (value vertices are dropped),
* without the environment captured at each vertex (control dependencies are kept),
* and without the vertices for plain operators and keywords (\`<-\`, \`=\`, \`+\`, \`|>\`, \`if\`, \`function\`, ...).

Edges survive only if both of their endpoints do. The query takes no further arguments.

${(0, doc_code_1.codeBlock)('r', exampleCode)}

${await (0, doc_query_1.showQuery)(shell, exampleCode, [{ type: 'dataflow-lens' }], { showCode: false, ctx })}

${(0, doc_structure_1.block)({
            type: 'NOTE',
            content: `This is a presentation aid, not a semantic one: the reduced graph is not a sound basis for slicing.
Use the ${(0, doc_query_1.linkToQueryOfName)('dataflow')} if you need the complete graph, or the ${(0, doc_query_1.linkToQueryOfName)('dataflow-cluster')} if you want the graph partitioned instead of shrunk.`
        })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('signature', {
    type: 'active',
    shortDescription: 'Inspects the signature database: packages, function signatures, source and documentation links.',
    functionName: signature_query_executor_1.executeSignatureQuery.name,
    functionFile: '../queries/catalog/signature-query/signature-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'library(dplyr)\nlead(1:10, n = 1)';
        return `
This query is the read-side interface to flowR's ${ctx.linkPage('wiki/Signature Database', 'signature database')}&mdash;the very same database
that resolves \`library()\` and \`::\` calls during the dataflow analysis. It lets you ask what flowR actually _knows_ about a package
or a function, without needing R or a network connection.

What you get back depends on how specific you are:

| Given | Result |
| ----- | :----- |
| nothing | a summary of the loaded databases |
| \`package\` | the full package view: version, CRAN links, dependencies, exports |
| \`package\` + \`function\` | the full function view: parameters, definition site, source and documentation links, S3 relations |
| a glob in either (\`gg*\`, \`geom_*\`) | the set of matching packages or functions |

The \`version\` property accepts an exact version, a glob (\`3.*\`), a semver range (\`>=3.0.0\`), or a release-date bound (\`<=2026\`, \`>=2021.05\`).
Without it, the release that flowR resolved for the analyzed script is used, so the signature you see is the one the analysis actually assumed.

Given a script such as:
${(0, doc_code_1.codeBlock)('r', exampleCode)}

we can inspect the signature of the function it calls:

${await (0, doc_query_1.showQuery)(shell, exampleCode, [{ type: 'signature', package: 'dplyr', function: 'lead' }], { showCode: false, collapseResult: true, ctx })}

The \`parameters\` and \`requiredParameters\` properties additionally filter by the _shape_ of a function, which is useful to find
functions you only half-remember: \`{ package: '*', parameters: ['data', 'mapping'] }\` finds every known function taking both of these.

${(0, doc_structure_1.block)({
            type: 'NOTE',
            content: `The results depend on which database shards are mounted; with none available the query reports that no database is loaded rather than failing.
See the ${ctx.linkPage('wiki/Signature Database')} page for the storage format, the configuration under ${ctx.linkConfig('solver.sigdb', true)}, and how to obtain further shards.
To find out what a script _uses_, reach for the ${(0, doc_query_1.linkToQueryOfName)('dependencies')}; to find out which versions it is compatible with, see the ${(0, doc_query_1.linkToQueryOfName)('guess-dep-versions')}.`
        })}
		`;
    }
});
(0, doc_query_1.registerQueryDocumentation)('guess-dep-versions', {
    type: 'active',
    shortDescription: 'Guesses the version range each dependency must have, from declared constraints and actual code usage.',
    functionName: guess_dep_versions_query_executor_1.executeGuessDepVersionsQuery.name,
    functionFile: '../queries/catalog/guess-dep-versions-query/guess-dep-versions-query-executor.ts',
    buildExplanation: async (shell, ctx) => {
        const exampleCode = 'library(dplyr)\nmutate(mtcars, across(everything(), round))';
        return `
A script rarely says which version of a package it needs, but it shows you. If it passes an argument that a function only
gained in some release, it cannot run on anything older. This query turns that observation into a concrete version range per dependency.

It combines two sources of evidence:

1. what the project **declares**: a \`DESCRIPTION\` range, an \`rproject.toml\` entry, a lockfile pin, and everything these imply transitively, and
2. what the code **does**: which package functions it calls and with which arguments, matched against the ${ctx.linkPage('wiki/Signature Database', 'signature database')}.

Every resulting bound carries its provenance, so the answer explains itself: each entry lists the \`evidence\` that produced it,
naming the function, the parameter, and the bound it implies.

Two things can raise a lower bound: calling a function that did not exist yet, or passing an argument that the
function only gained later. Consider a script calling \`dplyr::across\`:
${(0, doc_code_1.codeBlock)('r', exampleCode)}

\`across\` was only introduced in dplyr 1.0.0, so the script cannot run on anything older. The result names the function
that produced the bound:

${await (0, doc_query_1.showQuery)(shell, exampleCode, [{ type: 'guess-dep-versions' }], { showCode: false, collapseResult: true, ctx })}

The guess can be narrowed further:

* \`packages\` restricts it to the dependencies you care about,
* \`date\` caps every guess to releases available at that point in time (\`YYYY.MM.DD\`, also \`YYYY\` or \`YYYY.MM\`),
* \`clean\` ignores the declared constraints entirely and guesses purely from usage,
* \`disabled\` excludes individual evidence sources by name (repl: \`--disabled\` followed by their one-letter codes shown in the legend below, e.g. \`--disabled ds\` drops \`declared\` and \`signature\`),
* \`maxCandidates\` caps how many candidate versions are listed per dependency,
* \`maxIterations\` bounds the two fixpoint loops (packages constrain each other, so the guess is iterated until it settles), and
* \`explode\` additionally enumerates concrete version _combinations_ (\`order\`, \`prefer\`, and \`limit\` control which and how many).

Packages can also be tied to one shared version (the base/R packages always are), and ${ctx.linkConfig('solver.versionManagement.linkedVersionGroups', true)}
declares further groups. Such a package reports its partners in \`linkedWith\`, because its range is then no longer independent of theirs.

What one dependency requires of another (\`transitive\` evidence) is read from *every* version of it still in play:

* all of them require it: the guess is narrowed, by the weakest of their bounds,
* only some do: the evidence carries \`partial: true\` and never narrows, as another version avoids it.

A partial requirement still ties the two together. \`A 0.2.5\` needing \`B 0.2.1\` and \`A 0.3.0\` needing \`B 0.3.2\`
shrinks neither range, yet the versions are not free. Each package lists its \`coupledWith\` partners, and
\`runnableCombinations\` counts the tuples those couplings admit, against the plain product \`possibleCombinations\`
and, where the project declares constraints, against \`declaredCombinations\` (what those alone leave, so the share
says how much the guess added).

${(0, doc_structure_1.block)({
            type: 'NOTE',
            content: `This query needs the ${ctx.linkPage('wiki/Signature Database', 'signature database')}, and specifically a database carrying the _history_ of a package,
since bounding a version means comparing releases. Without one it returns no guesses and says so in its \`message\`.
See the ${(0, doc_query_1.linkToQueryOfName)('signature')} to inspect the signatures the guess is drawn from.`
        })}
		`;
    }
});
/**
 * https://github.com/flowr-analysis/flowr/wiki/Query-API
 */
class WikiQuery extends doc_maker_1.DocMaker {
    constructor() {
        super('wiki/Query API.md', module.filename, 'query API');
    }
    async text({ ctx, shell }) {
        (0, doc_query_1.assertAllQueriesDocumented)();
        /* the signature query documented here answers from the database, so its examples need one */
        (0, doc_sigdb_1.warnMissingSigDb)(this.getTarget());
        for (const [file, content] of Object.entries({
            ...await (0, doc_query_1.queryPages)(shell, ctx, 'active'),
            ...await (0, doc_query_1.queryPages)(shell, ctx, 'virtual')
        })) {
            this.writeSubFile(file, content);
        }
        return `
This page briefly summarizes flowR's query API, represented by the ${query_1.executeQueries.name} function in ${(0, doc_files_1.getFilePathMd)('../queries/query.ts')}.
Please see the ${ctx.linkPage('wiki/Interface')} wiki page for more information on how to access this API.

${(0, doc_structure_1.block)({
            type: 'NOTE',
            content: `
There are many ways to query a dataflow graph created by flowR.
For example, you can use the ${ctx.linkPage('wiki/Interface', '`request-query`', 'message-request-query')} message
with a running flowR server, or the ${(0, doc_cli_option_1.getReplCommand)('query')} command in the flowR ${ctx.linkPage('wiki/Interface', 'REPL', '-using-the-repl')}.

Also, check out the [${doc_files_1.FlowrGithubGroupName}/sample-analyzer-project-query](${doc_files_1.FlowrGithubBaseRef}/sample-analyzer-project-query) repository for a complete example project using the query API.
			`.trim()
        })}

## The Query Format

Queries are JSON arrays of query objects, each of which uses a \`type\` property to specify the query type.
In general, we separate two types of queries:

1. **Active Queries**: Are exactly what you would expect from a query (e.g., the ${(0, doc_query_1.linkToQueryOfName)('call-context')}). They fetch information from the dataflow graph.
2. **Virtual Queries**: Are used to structure your queries (e.g., the ${(0, doc_query_1.linkToQueryOfName)('compound')}).

We separate these from a concept perspective. 
For now, we support the following **active** queries (which we will refer to simply as a \`query\`):

${(0, doc_query_1.tocForQueryType)('active')}

Similarly, we support the following **virtual** queries: 

${(0, doc_query_1.tocForQueryType)('virtual')}

<details>


<summary>Detailed Query Format (Automatically Generated)</summary>

Although it is probably better to consult the detailed explanations, if you want to have a look at the schema, here is its description:

${(0, schema_1.describeSchema)((0, query_1.QueriesSchema)(), ansi_1.markdownFormatter)}

</details>

### Why Queries?

First, consider that you have a file like the following (of course, this is just a simple and artificial example):

\`\`\`r
${example_query_code_1.exampleQueryCode}
\`\`\`

<details> <summary>Dataflow Graph of the Example</summary>

${await (0, doc_dfg_1.printDfGraphForCode)(shell, example_query_code_1.exampleQueryCode, { showCode: false, ctx })}

</details>

&nbsp;

Additionally, consider that you are interested in all function calls which loads data with \`read_csv\`.
A simple \`regex\`-based query could look like this: \`^read_csv$\`.
However, this fails to incorporate
 
1. Syntax-based information (comments, strings, used as a variable, called as a higher-order function, ...)
2. Semantic information (e.g., \`read_csv\` is overwritten by a function with the same name)
3. Context information (e.g., calls like \`points\` may link to the current plot)

To solve this, flowR provides a query API which allows you to specify queries on the dataflow graph.
For the specific use-case stated, you could use the ${(0, doc_query_1.linkToQueryOfName)('call-context')} to find all calls to \`read_csv\` which refer functions that are not overwritten.

Just as an example, the following ${(0, doc_query_1.linkToQueryOfName)('call-context')} finds all calls to \`read_csv\` that are not overwritten:

${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode, [{ type: 'call-context', callName: '^read_csv$', callTargets: identify_link_to_last_call_relation_1.CallTargets.OnlyGlobal, kind: 'input', subkind: 'csv-file' }], { showCode: false, ctx })}

Every query is explained in detail on its own wiki page, linked from the overviews above.
`;
    }
}
exports.WikiQuery = WikiQuery;
//# sourceMappingURL=wiki-query.js.map