From a12a64325072f563ecf80060f984eb2e4634e0c5 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:10:53 +0100 Subject: [PATCH 01/17] docs(overview): add links to subsections --- wiki/Overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wiki/Overview.md b/wiki/Overview.md index b67b15c0c99..36b127f515f 100644 --- a/wiki/Overview.md +++ b/wiki/Overview.md @@ -60,8 +60,8 @@ The following sections explain how to use these features. _flowR_ itself has two main ways to operate: -- as a **server** which processes analysis and slicing requests (`--server` option) -- as a **read-eval-print loop** (REPL) that can be accessed directly from the command line (default option) +- as a [**server**](#the-server) which processes analysis and slicing requests (`--server` option) +- as a [**read-eval-print loop** (REPL)](#the-read-eval-print-loop-repl) that can be accessed directly from the command line (default option) Besides these two ways, there is a [Visual Studio Code extension](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr) that allows you to use _flowR_ directly from within the editor (it is available on [open-vsx](https://open-vsx.org/extension/code-inspect/vscode-flowr) as well). Similarly, we offer an [Addin for RStudio](https://github.com/flowr-analysis/rstudio-addin-flowr), as well as an [R package](https://github.com/flowr-analysis/flowr-r-adapter). From bdc409e1d16789fe945e324cb991553453535a3c Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:11:38 +0100 Subject: [PATCH 02/17] docs-fix(overview): update path --- wiki/Overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wiki/Overview.md b/wiki/Overview.md index 36b127f515f..222c12a5bce 100644 --- a/wiki/Overview.md +++ b/wiki/Overview.md @@ -67,9 +67,9 @@ Besides these two ways, there is a [Visual Studio Code extension](https://market Similarly, we offer an [Addin for RStudio](https://github.com/flowr-analysis/rstudio-addin-flowr), as well as an [R package](https://github.com/flowr-analysis/flowr-r-adapter). 🐳️ If you use the docker-version, simply starting the docker container in interactive mode drops you right into the REPL (`docker run -it --rm eagleoutice/flowr:latest`), while launching with the `--server` argument starts the server (`docker run -it --rm eagleoutice/flowr:latest --server`).\ -⚒️ If you compile the _flowR_ sources yourself, you can access _flowR_ by first building the sources (`npm run build`) and executing then the root script (`node dist/src/flowr.js`). +⚒️ If you compile the _flowR_ sources yourself, you can access _flowR_ by first building the sources (`npm run build`) and executing then the root script (`node dist/src/cli/flowr.js`). -Independent of your way of launching *flowr*, we will write simply `flowr` for either (🐳️) `docker run -it --rm eagleoutice/flowr:latest` or (⚒️) `node dist/src/flowr.js`. See the [setup](https://github.com/flowr-analysis/flowr/wiki/Setup) wiki page for more information on how to get _flowR_ running. +Independent of your way of launching *flowr*, we will write simply `flowr` for either (🐳️) `docker run -it --rm eagleoutice/flowr:latest` or (⚒️) `node dist/src/cli/flowr.js`. See the [setup](https://github.com/flowr-analysis/flowr/wiki/Setup) wiki page for more information on how to get _flowR_ running. ### The Read-Eval-Print Loop (REPL) From 79886dbd73e16d917f28c47fa25245f3acfb1754 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:34:49 +0100 Subject: [PATCH 03/17] docs: add examples from theses --- test/testfiles/df-shape.R | 22 ++++++++++++++++++++++ test/testfiles/linter.R | 8 ++++++++ 2 files changed, 30 insertions(+) create mode 100644 test/testfiles/df-shape.R create mode 100644 test/testfiles/linter.R diff --git a/test/testfiles/df-shape.R b/test/testfiles/df-shape.R new file mode 100644 index 00000000000..4053eb94f44 --- /dev/null +++ b/test/testfiles/df-shape.R @@ -0,0 +1,22 @@ +# Example R script for demonstrating the flowR dataframe shape inference +# Try it out in the REPL: +#R> :query @df-shape file://test/testfiles/df-shape.R + +library(dplyr) + +df1 <- data.frame( + id = 1:4, + age = c(25, 32, 35, 40), + score = c(90, 85, 88, 92) +) +df2 <- data.frame( + id = c(1, 2, 4), + category = c("A", "B", "A") +) +df3 <- df1 %>% + filter(age > 30) %>% + mutate(level = score^2) %>% + left_join(df2, by = "id") %>% + select(-age) + +print(df3$level) \ No newline at end of file diff --git a/test/testfiles/linter.R b/test/testfiles/linter.R new file mode 100644 index 00000000000..ff83b66105a --- /dev/null +++ b/test/testfiles/linter.R @@ -0,0 +1,8 @@ +# Example R script for demonstrating the flowR linter +# Try it out in the REPL: +# R> :query @linter rules:file-path-validity,absolute-file-paths,dead-code,seeded-randomness,deprecated-functions file://test/testfiles/linter.R + +my_data <- read.csv("C:/Users/Researcher/R/Reproducible.csv") +if (FALSE) { + dplyr::sample_n(my_data, 5) +} \ No newline at end of file From a55cabf5b760eb11263302454d27a59a3ff24502 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Wed, 5 Nov 2025 09:53:41 +0100 Subject: [PATCH 04/17] docs(repl): reference interface page --- wiki/Overview.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wiki/Overview.md b/wiki/Overview.md index 222c12a5bce..a0151aed7c9 100644 --- a/wiki/Overview.md +++ b/wiki/Overview.md @@ -74,7 +74,9 @@ Independent of your way of launching *flowr*, we will write simply `flowr` for e ### The Read-Eval-Print Loop (REPL) Once you launched _flowR_, you should see a small `R>` prompt. Use `:help` to receive instructions on how to use the REPL and what features are available (most prominently, you can access all [scripts](#calling-the-scripts-directly) simply by adding a colon before them). -In general, all commands start with a colon (`:`), everything else is interpreted as a R expression which is directly evaluated by the underlying R shell (however, due to security concerns, you need to start _flowR_ with `--r-session-access` and use the `r-shell` engine to allow this). The following GIF showcases a simple example session: +In general, all commands start with a colon (`:`), everything else is interpreted as a R expression which is directly evaluated by the underlying R shell (however, due to security concerns, you need to start _flowR_ with `--r-session-access` and use the `r-shell` engine to allow this). +See the [Interface](https://github.com/flowr-analysis/flowr/wiki/Interface) wiki page for more information on usage and the available commands. +The following GIF showcases a simple example session: ![Example of a simple REPL session](gif/repl-demo-opt.gif) From fddb4e32cf51a9afd6ab52b9deda6457b354a357 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Wed, 5 Nov 2025 10:01:25 +0100 Subject: [PATCH 05/17] docs(server): fix typo --- .../data/server/doc-data-server-messages.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/documentation/data/server/doc-data-server-messages.ts b/src/documentation/data/server/doc-data-server-messages.ts index db0e4d883aa..105386de59d 100644 --- a/src/documentation/data/server/doc-data-server-messages.ts +++ b/src/documentation/data/server/doc-data-server-messages.ts @@ -1,8 +1,4 @@ -import { - documentServerMessage, - documentServerMessageResponse, - inServerContext -} from '../../doc-util/doc-server-message'; +import { documentServerMessage, documentServerMessageResponse, inServerContext } from '../../doc-util/doc-server-message'; import { helloMessageDefinition } from '../../../cli/repl/server/messages/message-hello'; import { RShell } from '../../../r-bridge/shell'; import { DockerName } from '../../doc-util/doc-docker'; @@ -21,10 +17,7 @@ import { responseExecuteReplIntermediateMessage } from '../../../cli/repl/server/messages/message-repl'; -import { - requestQueryMessage, - responseQueryMessage -} from '../../../cli/repl/server/messages/message-query'; +import { requestQueryMessage, responseQueryMessage } from '../../../cli/repl/server/messages/message-query'; import { exampleQueryCode } from '../query/example-query-code'; import { requestLineageMessage, responseLineageMessage } from '../../../cli/repl/server/messages/message-lineage'; import { CallTargets } from '../../../queries/catalog/call-context-query/identify-link-to-last-call-relation'; @@ -99,7 +92,7 @@ ${ messages: [ { type: 'request', - description: `Let' suppose you simply want to analyze the following script:\n ${codeBlock('r', 'x <- 1\nx + 1')}\n For this, you can send the following request:`, + description: `Let's suppose you simply want to analyze the following script:\n ${codeBlock('r', 'x <- 1\nx + 1')}\n For this, you can send the following request:`, message: { type: 'request-file-analysis', id: '1', From 0ff34ada320b7ca33fc0d25386db53652143b255 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Wed, 5 Nov 2025 11:22:00 +0100 Subject: [PATCH 06/17] docs(search): remove unused duplicate code --- src/documentation/doc-util/doc-search.ts | 73 ------------------------ 1 file changed, 73 deletions(-) diff --git a/src/documentation/doc-util/doc-search.ts b/src/documentation/doc-util/doc-search.ts index 95142d5a9b0..b05327253bb 100644 --- a/src/documentation/doc-util/doc-search.ts +++ b/src/documentation/doc-util/doc-search.ts @@ -1,8 +1,5 @@ import type { RShell } from '../../r-bridge/shell'; -import type { SupportedQueryTypes } from '../../queries/query'; import { requestFromInput } from '../../r-bridge/retriever'; -import { getFilePathMd } from './doc-files'; -import type { SupportedVirtualQueryTypes } from '../../queries/virtual-query/virtual-queries'; import { printDfGraphForCode } from './doc-dfg'; import { codeBlock } from './doc-code'; import { printAsMs } from '../../util/text/time'; @@ -69,74 +66,4 @@ ${await printDfGraphForCode(shell, code, { showCode: false, switchCodeAndGraph: ${collapseResult ? '' : ''} `; - -} - -export interface QueryDocumentation { - readonly name: string; - readonly type: 'virtual' | 'active'; - readonly shortDescription: string; - readonly functionName: string; - readonly functionFile: string; - readonly buildExplanation: (shell: RShell) => Promise; -} - -export const RegisteredQueries = { - 'active': new Map(), - 'virtual': new Map() -}; - -export function registerQueryDocumentation(query: SupportedQueryTypes | SupportedVirtualQueryTypes, doc: QueryDocumentation) { - const map = RegisteredQueries[doc.type]; - if(map.has(query)) { - throw new Error(`Query ${query} already registered`); - } - map.set(query, doc); -} - -function linkify(name: string) { - return name.toLowerCase().replace(/ /g, '-'); -} - -export function linkToQueryOfName(id: SupportedQueryTypes | SupportedVirtualQueryTypes) { - const query = RegisteredQueries.active.get(id) ?? RegisteredQueries.virtual.get(id); - if(!query) { - throw new Error(`Query ${id} not found`); - } - return `[${query.name}](#${linkify(query.name)})`; -} - -export function tocForQueryType(type: 'active' | 'virtual') { - const queries = [...RegisteredQueries[type].entries()].sort(([,{ name: a }], [, { name: b }]) => a.localeCompare(b)); - const result: string[] = []; - for(const [id, { name, shortDescription }] of queries) { - result.push(`1. [${name}](#${linkify(name)}) (\`${id}\`):\\\n ${shortDescription}`); - } - return result.join('\n'); -} - -async function explainQuery(shell: RShell, { name, functionName, functionFile, buildExplanation }: QueryDocumentation) { - return ` -### ${name} - -${await buildExplanation(shell)} - -
- -Implementation Details - -Responsible for the execution of the ${name} query is \`${functionName}\` in ${getFilePathMd(functionFile)}. - -
- -`; -} - -export async function explainQueries(shell: RShell, type: 'active' | 'virtual'): Promise { - const queries = [...RegisteredQueries[type].entries()].sort(([,{ name: a }], [, { name: b }]) => a.localeCompare(b)); - const result: string[] = []; - for(const [,doc] of queries) { - result.push(await explainQuery(shell, doc)); - } - return result.join(`\n${'-'.repeat(5)}\n\n`); } From e3895b1a617bda4ee840fe478e0e7411cdc9d8e5 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Wed, 5 Nov 2025 11:26:17 +0100 Subject: [PATCH 07/17] docs(query): add shorthand hints --- src/documentation/doc-util/doc-query.ts | 14 +++++++++- src/documentation/print-query-wiki.ts | 37 ++++++++++++++++++------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/documentation/doc-util/doc-query.ts b/src/documentation/doc-util/doc-query.ts index eaa1e59ddc4..2dbf75fa878 100644 --- a/src/documentation/doc-util/doc-query.ts +++ b/src/documentation/doc-util/doc-query.ts @@ -12,17 +12,23 @@ import { printAsMs } from '../../util/text/time'; import { asciiSummaryOfQueryResult } from '../../queries/query-print'; import { FlowrAnalyzerBuilder } from '../../project/flowr-analyzer-builder'; import { getReplCommand } from './doc-cli-option'; +import type { SingleSlicingCriterion } from '../../slicing/criterion/parse'; export interface ShowQueryOptions { readonly showCode?: boolean; readonly collapseResult?: boolean; readonly collapseQuery?: boolean; + readonly shorthand?: string; } export async function showQuery< Base extends SupportedQueryTypes, VirtualArguments extends VirtualCompoundConstraint = VirtualCompoundConstraint ->(shell: RShell, code: string, queries: Queries, { showCode, collapseResult, collapseQuery }: ShowQueryOptions = {}): Promise { +>( + shell: RShell, code: string, + queries: Queries, + { showCode, collapseResult, collapseQuery, shorthand }: ShowQueryOptions = {} +): Promise { const now = performance.now(); const analyzer = await new FlowrAnalyzerBuilder(requestFromInput(code)).setParser(shell).build(); const results = await analyzer.query(queries); @@ -40,6 +46,8 @@ ${codeBlock('json', collapseQuery ? str.split('\n').join(' ').replace(/([{[])\s{ ${(function() { if(queries.length === 1 && Object.keys(queries[0]).length === 1) { return `(This query can be shortened to \`@${queries[0].type}\` when used within the REPL command ${getReplCommand('query')}).`; + } else if(shorthand) { + return `(This query can be shortened to \`@${queries[0].type} ${shorthand}\` when used within the REPL command ${getReplCommand('query')}).`; } else { return ''; } @@ -102,6 +110,10 @@ export function registerQueryDocumentation(query: SupportedQueryTypes | Supporte map.set(query, doc); } +export function sliceQueryShorthand(criterion: SingleSlicingCriterion, code: string) { + return `(${criterion}) "${code}"`; +} + function linkify(name: string) { return name.toLowerCase().replace(/ /g, '-'); } diff --git a/src/documentation/print-query-wiki.ts b/src/documentation/print-query-wiki.ts index 98c7353be4d..1f09ddcb174 100644 --- a/src/documentation/print-query-wiki.ts +++ b/src/documentation/print-query-wiki.ts @@ -9,6 +9,7 @@ import { linkToQueryOfName, registerQueryDocumentation, showQuery, + sliceQueryShorthand, tocForQueryType } from './doc-util/doc-query'; import { describeSchema } from '../util/schema'; @@ -44,6 +45,7 @@ import { documentReplSession } from './doc-util/doc-repl'; import { executeHigherOrderQuery } from '../queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor'; +import type { SlicingCriteria } from '../slicing/criterion/parse'; registerQueryDocumentation('call-context', { @@ -194,6 +196,7 @@ registerQueryDocumentation('lineage', { functionFile: '../queries/catalog/lineage-query/lineage-query-executor.ts', buildExplanation: async(shell: RShell) => { const exampleCode = 'x <- 1\nx'; + const criterion = '2@x'; return ` This query calculates the _lineage_ of a given slicing criterion. The lineage traces back all parts that the @@ -207,8 +210,8 @@ For this, we use the criterion \`2@x\` (which is the first use of \`x\` in the s ${ await showQuery(shell, exampleCode, [{ type: 'lineage', - criterion: '2@x' - }], { showCode: false }) + criterion: criterion + }], { showCode: false, shorthand: sliceQueryShorthand(criterion, exampleCode) }) } In this simple scenario, the _lineage_ is equivalent to the slice (and in-fact the complete code). @@ -261,6 +264,7 @@ registerQueryDocumentation('resolve-value', { functionFile: '../queries/catalog/resolve-value-query/resolve-value-query-executor.ts', buildExplanation: async(shell: RShell) => { const exampleCode = 'x <- 1\nprint(x)'; + const criteria = ['2@x'] as SlicingCriteria; 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 [Interface](${FlowrWikiBaseRef}/Interface) wiki page for more information). @@ -269,8 +273,8 @@ Using the example code \`${exampleCode}\` (with the \`print(x)\` in the second l ${ await showQuery(shell, exampleCode, [{ type: 'resolve-value', - criteria: ['2@x'] - }], { showCode: true }) + criteria: criteria + }], { showCode: true, shorthand: sliceQueryShorthand(criteria[0], exampleCode) }) } `; } @@ -306,6 +310,7 @@ registerQueryDocumentation('origin', { functionFile: '../queries/catalog/origin-query/origin-query-executor.ts', buildExplanation: async(shell: RShell) => { 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. @@ -314,8 +319,8 @@ Using the example code \`${exampleCode}\` (with the \`print(x)\` in the second l ${ await showQuery(shell, exampleCode, [{ type: 'origin', - criterion: '2@x' - }], { showCode: true }) + criterion: criterion + }], { showCode: true, shorthand: sliceQueryShorthand(criterion, exampleCode) }) } `; } @@ -411,7 +416,7 @@ ${ }], { showCode: false, collapseQuery: true, collapseResult: true }) } -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: +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 documentReplSession(shell, [ @@ -513,6 +518,7 @@ registerQueryDocumentation('static-slice', { functionFile: '../queries/catalog/static-slice-query/static-slice-query-executor.ts', buildExplanation: async(shell: RShell) => { const exampleCode = 'x <- 1\ny <- 2\nx'; + const criteria = ['3@x'] as SlicingCriteria; 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). @@ -526,8 +532,8 @@ If you are interested in the parts required for the use of \`x\` in the last lin ${ await showQuery(shell, exampleCode, [{ type: 'static-slice', - criteria: ['3@x'] - }], { showCode: false }) + criteria: criteria + }], { showCode: false, shorthand: sliceQueryShorthand(criteria[0], exampleCode) }) } In general, you may be uninterested in seeing the reconstructed version and want to save some computation time, for this, @@ -637,7 +643,18 @@ ${ }], { showCode: false, collapseQuery: true }) } -You can also configure which rules to apply and what settings to use for these rules. +You can also configure which rules to apply and what settings to use for these rules: +${ + await showQuery(shell, exampleCode, [{ + type: 'linter', + rules: ['file-path-validity'], + }], { + showCode: false, + collapseQuery: true, + shorthand: `rules:file-path-validity "${exampleCode}"` + }) +} + We welcome any feedback and suggestions for new rules on this (consider opening a [new issue](${NewIssueUrl})). `; } From 0361e434200b7f6533367bf2257e5721d690fab9 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Wed, 5 Nov 2025 11:26:36 +0100 Subject: [PATCH 08/17] docs(repl): add tab completion hint --- src/documentation/print-interface-wiki.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/documentation/print-interface-wiki.ts b/src/documentation/print-interface-wiki.ts index df80a34128b..9ec96faf72d 100644 --- a/src/documentation/print-interface-wiki.ts +++ b/src/documentation/print-interface-wiki.ts @@ -116,10 +116,12 @@ for communication (although you can access the REPL using the server as well, with the [REPL Request](#message-request-repl-execution) message). The read-eval-print loop (REPL) works relatively simple. -You can submit an expression (using enter), +You can submit an expression (using Enter), which is interpreted as an R expression by default but interpreted as a *command* if it starts with a colon (\`:\`). The best command to get started with the REPL is ${getReplCommand('help')}. -Besides, you can leave the REPL either with the command ${getReplCommand('quit')} or by pressing CTRL+C twice. +Besides, you can leave the REPL either with the command ${getReplCommand('quit')} or by pressing Ctrl+C twice. +When writing a *command*, you may press Tab to get a list of completions, if available. +Multiple commands can be entered in a single line by separating them with a semicolon (\`;\`), e.g. \`:parse "x<-2";:df*\`. > [!NOTE] > If you develop flowR, you may want to launch the repl using the \`npm run main-dev\` command, this way, you get a non-minified version of flowR with debug information and hot-reloading of source files. From 276df834c2b426b8e701b8619257d1806c673f95 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:04:26 +0100 Subject: [PATCH 09/17] docs-fix(repl): escape newlines in repl line --- src/documentation/doc-util/doc-escape.ts | 4 ++++ src/documentation/print-query-wiki.ts | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/documentation/doc-util/doc-escape.ts b/src/documentation/doc-util/doc-escape.ts index cf4db1039f2..e90cbda8d4c 100644 --- a/src/documentation/doc-util/doc-escape.ts +++ b/src/documentation/doc-util/doc-escape.ts @@ -17,3 +17,7 @@ export function escapeHTML(str: string | undefined): string | undefined { }[tag] ?? tag) ); } + +export function escapeNewline(str: string): string { + return str.replace(/\n/g, '\\n'); +} diff --git a/src/documentation/print-query-wiki.ts b/src/documentation/print-query-wiki.ts index 1f09ddcb174..a5f6b192e2a 100644 --- a/src/documentation/print-query-wiki.ts +++ b/src/documentation/print-query-wiki.ts @@ -46,6 +46,7 @@ import { executeHigherOrderQuery } from '../queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor'; import type { SlicingCriteria } from '../slicing/criterion/parse'; +import { escapeNewline } from './doc-util/doc-escape'; registerQueryDocumentation('call-context', { @@ -211,7 +212,7 @@ ${ await showQuery(shell, exampleCode, [{ type: 'lineage', criterion: criterion - }], { showCode: false, shorthand: sliceQueryShorthand(criterion, exampleCode) }) + }], { showCode: false, shorthand: sliceQueryShorthand(criterion, escapeNewline(exampleCode)) }) } In this simple scenario, the _lineage_ is equivalent to the slice (and in-fact the complete code). @@ -274,7 +275,7 @@ ${ await showQuery(shell, exampleCode, [{ type: 'resolve-value', criteria: criteria - }], { showCode: true, shorthand: sliceQueryShorthand(criteria[0], exampleCode) }) + }], { showCode: true, shorthand: sliceQueryShorthand(criteria[0], escapeNewline(exampleCode)) }) } `; } @@ -320,7 +321,7 @@ ${ await showQuery(shell, exampleCode, [{ type: 'origin', criterion: criterion - }], { showCode: true, shorthand: sliceQueryShorthand(criterion, exampleCode) }) + }], { showCode: true, shorthand: sliceQueryShorthand(criterion, escapeNewline(exampleCode)) }) } `; } @@ -533,7 +534,7 @@ ${ await showQuery(shell, exampleCode, [{ type: 'static-slice', criteria: criteria - }], { showCode: false, shorthand: sliceQueryShorthand(criteria[0], exampleCode) }) + }], { showCode: false, shorthand: sliceQueryShorthand(criteria[0], escapeNewline(exampleCode)) }) } In general, you may be uninterested in seeing the reconstructed version and want to save some computation time, for this, From 970c4f38b7d867a32ba6e748be05b5c494eb7108 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Fri, 7 Nov 2025 12:49:28 +0100 Subject: [PATCH 10/17] docs-fix(repl): queries optionally supporting slice criteria --- src/documentation/doc-util/doc-query.ts | 4 +-- src/documentation/print-query-wiki.ts | 28 +++++++++++++++---- .../location-map-query-format.ts | 2 +- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/documentation/doc-util/doc-query.ts b/src/documentation/doc-util/doc-query.ts index 2dbf75fa878..81eb931b0fc 100644 --- a/src/documentation/doc-util/doc-query.ts +++ b/src/documentation/doc-util/doc-query.ts @@ -110,8 +110,8 @@ export function registerQueryDocumentation(query: SupportedQueryTypes | Supporte map.set(query, doc); } -export function sliceQueryShorthand(criterion: SingleSlicingCriterion, code: string) { - return `(${criterion}) "${code}"`; +export function sliceQueryShorthand(criterion: SingleSlicingCriterion, code: string, forward?: boolean) { + return `(${criterion})${forward ? 'f' : ''} "${code}"`; } function linkify(name: string) { diff --git a/src/documentation/print-query-wiki.ts b/src/documentation/print-query-wiki.ts index a5f6b192e2a..4b483a9f815 100644 --- a/src/documentation/print-query-wiki.ts +++ b/src/documentation/print-query-wiki.ts @@ -45,7 +45,7 @@ import { documentReplSession } from './doc-util/doc-repl'; import { executeHigherOrderQuery } from '../queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor'; -import type { SlicingCriteria } from '../slicing/criterion/parse'; +import type { SingleSlicingCriterion, SlicingCriteria } from '../slicing/criterion/parse'; import { escapeNewline } from './doc-util/doc-escape'; @@ -439,6 +439,7 @@ registerQueryDocumentation('df-shape', { functionFile: '../queries/catalog/df-shape-query/df-shape-query-format.ts', buildExplanation: async(shell: RShell) => { const exampleCode = 'x <- data.frame(a=1:3)\nfilter(x, FALSE)'; + const criterion = '2@x' as SingleSlicingCriterion; return ` This query infers all shapes of dataframes within the code. For example, you can use: ${ @@ -446,6 +447,14 @@ ${ type: 'df-shape' }], { showCode: true, collapseQuery: true }) } + +The query also accepts an optional slice criterion that allows to filter the results to only include the shape of a specific data frame. For example: +${ + await showQuery(shell, exampleCode, [{ + type: 'df-shape', + criterion: criterion + }], { showCode: true, collapseQuery: true, shorthand: sliceQueryShorthand(criterion, escapeNewline(exampleCode)) }) +} `; } }); @@ -519,7 +528,6 @@ registerQueryDocumentation('static-slice', { functionFile: '../queries/catalog/static-slice-query/static-slice-query-executor.ts', buildExplanation: async(shell: RShell) => { const exampleCode = 'x <- 1\ny <- 2\nx'; - const criteria = ['3@x'] as SlicingCriteria; 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). @@ -533,8 +541,8 @@ If you are interested in the parts required for the use of \`x\` in the last lin ${ await showQuery(shell, exampleCode, [{ type: 'static-slice', - criteria: criteria - }], { showCode: false, shorthand: sliceQueryShorthand(criteria[0], escapeNewline(exampleCode)) }) + criteria: ['3@x'] as SlicingCriteria + }], { showCode: false, shorthand: sliceQueryShorthand('3@x', escapeNewline(exampleCode)) }) } In general, you may be uninterested in seeing the reconstructed version and want to save some computation time, for this, @@ -557,7 +565,7 @@ ${ type: 'static-slice', criteria: ['1@x'], direction: SliceDirection.Forward - }], { showCode: false }) + }], { showCode: false, shorthand: sliceQueryShorthand('1@x', escapeNewline(exampleCode), true) }) } You can disable [magic comments](${FlowrWikiBaseRef}/Interface#slice-magic-comments) using the \`noMagicComments\` flag. @@ -739,6 +747,7 @@ registerQueryDocumentation('location-map', { files: [path.resolve('./src/util/range.ts')], }); const exampleCode = 'x + 1\nx * 2'; + const criteria = ['2@x'] as SlicingCriteria; return ` A query like the ${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. @@ -755,6 +764,15 @@ ${ }], { showCode: false, collapseQuery: true }) } +The query also accepts a list of slice criteria to filter the results to only include the locations of specific nodes. For example: + +${ + await showQuery(shell, exampleCode, [{ + type: 'location-map', + ids: criteria + }], { showCode: false, collapseQuery: true, shorthand: sliceQueryShorthand(criteria[0], escapeNewline(exampleCode)) }) +} + All locations are given as a ${shortLink('SourceRange', types.info)} paired with the file id in the format \`[file-id, [start-line, start-column, end-line, end-column]]\`. `; diff --git a/src/queries/catalog/location-map-query/location-map-query-format.ts b/src/queries/catalog/location-map-query/location-map-query-format.ts index 1398bc40709..ca42c03eba5 100644 --- a/src/queries/catalog/location-map-query/location-map-query-format.ts +++ b/src/queries/catalog/location-map-query/location-map-query-format.ts @@ -28,7 +28,7 @@ export interface LocationMapQueryResult extends BaseQueryResult { } } -function locationMapLineParser(output: ReplOutput, line: readonly string[], _config: FlowrConfigOptions): ParsedQueryLine<'location-map'> { +function locationMapLineParser(_output: ReplOutput, line: readonly string[], _config: FlowrConfigOptions): ParsedQueryLine<'location-map'> { const criteria = sliceCriteriaParser(line[0]); return { query: { From ea715469ab0bb57221b773f5b578675d37520a47 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Fri, 7 Nov 2025 14:43:03 +0100 Subject: [PATCH 11/17] docs-fix(repl): change df-shape query explanation --- src/documentation/print-query-wiki.ts | 2 +- src/queries/catalog/df-shape-query/df-shape-query-format.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/documentation/print-query-wiki.ts b/src/documentation/print-query-wiki.ts index 4b483a9f815..50007bce808 100644 --- a/src/documentation/print-query-wiki.ts +++ b/src/documentation/print-query-wiki.ts @@ -448,7 +448,7 @@ ${ }], { showCode: true, collapseQuery: true }) } -The query also accepts an optional slice criterion that allows to filter the results to only include the shape of a specific data frame. For example: +The query also accepts an optional slice criterion to narrow the results to a specific node. For example: ${ await showQuery(shell, exampleCode, [{ type: 'df-shape', diff --git a/src/queries/catalog/df-shape-query/df-shape-query-format.ts b/src/queries/catalog/df-shape-query/df-shape-query-format.ts index b0128bf085f..d04a3c83a5e 100644 --- a/src/queries/catalog/df-shape-query/df-shape-query-format.ts +++ b/src/queries/catalog/df-shape-query/df-shape-query-format.ts @@ -21,7 +21,7 @@ export interface DfShapeQueryResult extends BaseQueryResult { domains: DataFrameStateDomain | Map } -function dfShapeQueryLineParser(output: ReplOutput, line: readonly string[], _config: FlowrConfigOptions): ParsedQueryLine<'df-shape'> { +function dfShapeQueryLineParser(_output: ReplOutput, line: readonly string[], _config: FlowrConfigOptions): ParsedQueryLine<'df-shape'> { const criterion = sliceCriterionParser(line[0]); return { From 61b539d7b7c84c63040a3c2ce02038f4a3777742 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:17:14 +0100 Subject: [PATCH 12/17] docs-fix(repl): add explanation for multiple criteria --- src/documentation/doc-util/doc-query.ts | 18 +++++++++--------- src/documentation/print-query-wiki.ts | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/documentation/doc-util/doc-query.ts b/src/documentation/doc-util/doc-query.ts index 81eb931b0fc..694364bac1f 100644 --- a/src/documentation/doc-util/doc-query.ts +++ b/src/documentation/doc-util/doc-query.ts @@ -15,10 +15,11 @@ import { getReplCommand } from './doc-cli-option'; import type { SingleSlicingCriterion } from '../../slicing/criterion/parse'; export interface ShowQueryOptions { - readonly showCode?: boolean; - readonly collapseResult?: boolean; - readonly collapseQuery?: boolean; - readonly shorthand?: string; + readonly showCode?: boolean; + readonly collapseResult?: boolean; + readonly collapseQuery?: boolean; + readonly shorthand?: string; + readonly multipleCriteria?: boolean; } export async function showQuery< @@ -27,7 +28,7 @@ export async function showQuery< >( shell: RShell, code: string, queries: Queries, - { showCode, collapseResult, collapseQuery, shorthand }: ShowQueryOptions = {} + { showCode, collapseResult, collapseQuery, shorthand, multipleCriteria }: ShowQueryOptions = {} ): Promise { const now = performance.now(); const analyzer = await new FlowrAnalyzerBuilder(requestFromInput(code)).setParser(shell).build(); @@ -44,10 +45,9 @@ The analysis required _${printAsMs(duration)}_ (including parsing and normalizat ${codeBlock('json', collapseQuery ? str.split('\n').join(' ').replace(/([{[])\s{2,}/g,'$1 ').replace(/\s{2,}([\]}])/g,' $1') : str)} ${(function() { - if(queries.length === 1 && Object.keys(queries[0]).length === 1) { - return `(This query can be shortened to \`@${queries[0].type}\` when used within the REPL command ${getReplCommand('query')}).`; - } else if(shorthand) { - return `(This query can be shortened to \`@${queries[0].type} ${shorthand}\` when used within the REPL command ${getReplCommand('query')}).`; + if((queries.length === 1 && Object.keys(queries[0]).length === 1) || shorthand) { + return `(This query can be shortened to \`@${queries[0].type}${shorthand ? ' ' + shorthand : ''}\` when used within the REPL command ${getReplCommand('query')}` + + `${multipleCriteria ? '. Multiple criteria can be given by separating them with a semicolon: `(criterion1;criterion2;...;criterionN)`' : ''}).`; } else { return ''; } diff --git a/src/documentation/print-query-wiki.ts b/src/documentation/print-query-wiki.ts index 50007bce808..dd0cd646357 100644 --- a/src/documentation/print-query-wiki.ts +++ b/src/documentation/print-query-wiki.ts @@ -275,7 +275,7 @@ ${ await showQuery(shell, exampleCode, [{ type: 'resolve-value', criteria: criteria - }], { showCode: true, shorthand: sliceQueryShorthand(criteria[0], escapeNewline(exampleCode)) }) + }], { showCode: true, multipleCriteria: true, shorthand: sliceQueryShorthand(criteria[0], escapeNewline(exampleCode)) }) } `; } @@ -542,7 +542,7 @@ ${ await showQuery(shell, exampleCode, [{ type: 'static-slice', criteria: ['3@x'] as SlicingCriteria - }], { showCode: false, shorthand: sliceQueryShorthand('3@x', escapeNewline(exampleCode)) }) + }], { showCode: false, multipleCriteria: true, shorthand: sliceQueryShorthand('3@x', escapeNewline(exampleCode)) }) } In general, you may be uninterested in seeing the reconstructed version and want to save some computation time, for this, @@ -565,7 +565,7 @@ ${ type: 'static-slice', criteria: ['1@x'], direction: SliceDirection.Forward - }], { showCode: false, shorthand: sliceQueryShorthand('1@x', escapeNewline(exampleCode), true) }) + }], { showCode: false, multipleCriteria: true, shorthand: sliceQueryShorthand('1@x', escapeNewline(exampleCode), true) }) } You can disable [magic comments](${FlowrWikiBaseRef}/Interface#slice-magic-comments) using the \`noMagicComments\` flag. @@ -770,7 +770,7 @@ ${ await showQuery(shell, exampleCode, [{ type: 'location-map', ids: criteria - }], { showCode: false, collapseQuery: true, shorthand: sliceQueryShorthand(criteria[0], escapeNewline(exampleCode)) }) + }], { showCode: false, collapseQuery: true, multipleCriteria: true, shorthand: sliceQueryShorthand(criteria[0], escapeNewline(exampleCode)) }) } All locations are given as a ${shortLink('SourceRange', types.info)} paired with the file id in the format \`[file-id, [start-line, start-column, end-line, end-column]]\`. From a2c69d035ba2927f546a5a3511cc99782b21e950 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Sat, 8 Nov 2025 12:21:12 +0100 Subject: [PATCH 13/17] docs-fix(repl): also escape carriage return --- src/documentation/doc-util/doc-escape.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/documentation/doc-util/doc-escape.ts b/src/documentation/doc-util/doc-escape.ts index e90cbda8d4c..29b84eab01b 100644 --- a/src/documentation/doc-util/doc-escape.ts +++ b/src/documentation/doc-util/doc-escape.ts @@ -18,6 +18,14 @@ export function escapeHTML(str: string | undefined): string | undefined { ); } +/** + * Escapes newline characters in a string (Supports Windows and Unix newlines). + * + * @param str - The string to escape + * @returns The escaped string + */ export function escapeNewline(str: string): string { - return str.replace(/\n/g, '\\n'); + return str.replace(/([\n\r])/g, (match) => { + return match == '\n' ? '\\n' : '\\r'; + }); } From 9e65b594afa6efc13cd2d0fff1f4d69a0d047720 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Sat, 8 Nov 2025 12:50:12 +0100 Subject: [PATCH 14/17] docs-fix(repl): review comments --- src/documentation/print-interface-wiki.ts | 4 +++- test/testfiles/linter.R | 2 +- wiki/Overview.md | 7 +++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/documentation/print-interface-wiki.ts b/src/documentation/print-interface-wiki.ts index 9ec96faf72d..2bfd39775d6 100644 --- a/src/documentation/print-interface-wiki.ts +++ b/src/documentation/print-interface-wiki.ts @@ -121,7 +121,9 @@ which is interpreted as an R expression by default but interpreted as a *co The best command to get started with the REPL is ${getReplCommand('help')}. Besides, you can leave the REPL either with the command ${getReplCommand('quit')} or by pressing Ctrl+C twice. When writing a *command*, you may press Tab to get a list of completions, if available. -Multiple commands can be entered in a single line by separating them with a semicolon (\`;\`), e.g. \`:parse "x<-2";:df*\`. +Multiple commands can be entered in a single line by separating them with a semicolon (\`;\`), e.g. \`:parse "x<-2"; :df*\`. +If a command is given without R code, the REPL will re-use R code given in a previous command. +The prior example will hence return the dataflow graph for \`"x <- 2"\`. > [!NOTE] > If you develop flowR, you may want to launch the repl using the \`npm run main-dev\` command, this way, you get a non-minified version of flowR with debug information and hot-reloading of source files. diff --git a/test/testfiles/linter.R b/test/testfiles/linter.R index ff83b66105a..e092c00c80d 100644 --- a/test/testfiles/linter.R +++ b/test/testfiles/linter.R @@ -1,6 +1,6 @@ # Example R script for demonstrating the flowR linter # Try it out in the REPL: -# R> :query @linter rules:file-path-validity,absolute-file-paths,dead-code,seeded-randomness,deprecated-functions file://test/testfiles/linter.R +# R> :query @linter rules:absolute-file-paths,dead-code file://test/testfiles/linter.R my_data <- read.csv("C:/Users/Researcher/R/Reproducible.csv") if (FALSE) { diff --git a/wiki/Overview.md b/wiki/Overview.md index a0151aed7c9..4b45f170701 100644 --- a/wiki/Overview.md +++ b/wiki/Overview.md @@ -3,7 +3,7 @@ If you have never used _flowR_ before, please refer to the [setup](https://githu - [_flowR_'s Modules](#flowrs-modules) -- [Using _flowR_](#using-flowr) +- [Using _flowR_ from the outside](#using-flowr-from-the-outside) - [The Read-Eval-Print Loop (REPL)](#the-read-eval-print-loop-repl) - [The Server](#the-server) - [Calling the Scripts Directly](#calling-the-scripts-directly) @@ -43,8 +43,7 @@ with the important components directly related to the analysis highlighted accor Primarily, _flowR_ provides a dataflow analysis framework for the [*R*](https://www.r-project.org/) programming language. Its subcomponents (like the custom [R bridge](https://github.com/flowr-analysis/flowr/tree/main/src/r-bridge) or the internals of the static [dataflow analysis]("https://github.com/flowr-analysis/flowr/tree/main/src/dataflow)) are not important if you simply wish to use _flowR_. -If you wish to use flowR, check out one of its extensions (e.g., the [VS Code extension](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr)) -or its coding API with the [`FlowrAnalyzer`](https://github.com/flowr-analysis/flowr/wiki/Core). +If you wish to use flowR, check out one of its extensions (e.g., the [VS Code extension](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr)), the [REPL and server interfaces](#using-_flowr_-from-the-outside) or its coding API with the [`FlowrAnalyzer`](https://github.com/flowr-analysis/flowr/wiki/Core). The benchmark module is only of interest if you want to benchmark/measure the runtime performance and reduction of the slicer. It is available with the [`benchmark`](#benchmark-the-slicer) script. @@ -56,7 +55,7 @@ The [utility](https://github.com/flowr-analysis/flowr/tree/main/src/util) module The following sections explain how to use these features. -## Using _flowR_ +## Using _flowR_ from the outside _flowR_ itself has two main ways to operate: From 133f055359c301c876add3f8fe4f604d35b079a3 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Sat, 8 Nov 2025 12:59:27 +0100 Subject: [PATCH 15/17] docs-fix(repl): remove empty line --- src/documentation/data/server/doc-data-server-messages.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/documentation/data/server/doc-data-server-messages.ts b/src/documentation/data/server/doc-data-server-messages.ts index 105386de59d..c478c94c3eb 100644 --- a/src/documentation/data/server/doc-data-server-messages.ts +++ b/src/documentation/data/server/doc-data-server-messages.ts @@ -16,7 +16,6 @@ import { responseExecuteReplEndMessage, responseExecuteReplIntermediateMessage } from '../../../cli/repl/server/messages/message-repl'; - import { requestQueryMessage, responseQueryMessage } from '../../../cli/repl/server/messages/message-query'; import { exampleQueryCode } from '../query/example-query-code'; import { requestLineageMessage, responseLineageMessage } from '../../../cli/repl/server/messages/message-lineage'; From ebc852911f3bc765b413a333914cd3cca9678bbd Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Sat, 8 Nov 2025 16:04:05 +0100 Subject: [PATCH 16/17] docs-fix(repl): add examples for multiple criteria --- src/documentation/doc-util/doc-query.ts | 20 ++++++++--------- src/documentation/print-query-wiki.ts | 29 +++++++++++++------------ 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/documentation/doc-util/doc-query.ts b/src/documentation/doc-util/doc-query.ts index 694364bac1f..60e33965bc1 100644 --- a/src/documentation/doc-util/doc-query.ts +++ b/src/documentation/doc-util/doc-query.ts @@ -12,14 +12,13 @@ import { printAsMs } from '../../util/text/time'; import { asciiSummaryOfQueryResult } from '../../queries/query-print'; import { FlowrAnalyzerBuilder } from '../../project/flowr-analyzer-builder'; import { getReplCommand } from './doc-cli-option'; -import type { SingleSlicingCriterion } from '../../slicing/criterion/parse'; +import type { SlicingCriteria } from '../../slicing/criterion/parse'; export interface ShowQueryOptions { - readonly showCode?: boolean; - readonly collapseResult?: boolean; - readonly collapseQuery?: boolean; - readonly shorthand?: string; - readonly multipleCriteria?: boolean; + readonly showCode?: boolean; + readonly collapseResult?: boolean; + readonly collapseQuery?: boolean; + readonly shorthand?: string; } export async function showQuery< @@ -28,7 +27,7 @@ export async function showQuery< >( shell: RShell, code: string, queries: Queries, - { showCode, collapseResult, collapseQuery, shorthand, multipleCriteria }: ShowQueryOptions = {} + { showCode, collapseResult, collapseQuery, shorthand }: ShowQueryOptions = {} ): Promise { const now = performance.now(); const analyzer = await new FlowrAnalyzerBuilder(requestFromInput(code)).setParser(shell).build(); @@ -46,8 +45,7 @@ ${codeBlock('json', collapseQuery ? str.split('\n').join(' ').replace(/([{[])\s{ ${(function() { if((queries.length === 1 && Object.keys(queries[0]).length === 1) || shorthand) { - return `(This query can be shortened to \`@${queries[0].type}${shorthand ? ' ' + shorthand : ''}\` when used within the REPL command ${getReplCommand('query')}` + - `${multipleCriteria ? '. Multiple criteria can be given by separating them with a semicolon: `(criterion1;criterion2;...;criterionN)`' : ''}).`; + return `(This query can be shortened to \`@${queries[0].type}${shorthand ? ' ' + shorthand : ''}\` when used within the REPL command ${getReplCommand('query')}).`; } else { return ''; } @@ -110,8 +108,8 @@ export function registerQueryDocumentation(query: SupportedQueryTypes | Supporte map.set(query, doc); } -export function sliceQueryShorthand(criterion: SingleSlicingCriterion, code: string, forward?: boolean) { - return `(${criterion})${forward ? 'f' : ''} "${code}"`; +export function sliceQueryShorthand(criteria: SlicingCriteria, code: string, forward?: boolean) { + return `(${(criteria.join(';'))})${forward ? 'f' : ''} "${code}"`; } function linkify(name: string) { diff --git a/src/documentation/print-query-wiki.ts b/src/documentation/print-query-wiki.ts index dd0cd646357..42f258e6a4f 100644 --- a/src/documentation/print-query-wiki.ts +++ b/src/documentation/print-query-wiki.ts @@ -212,7 +212,7 @@ ${ await showQuery(shell, exampleCode, [{ type: 'lineage', criterion: criterion - }], { showCode: false, shorthand: sliceQueryShorthand(criterion, escapeNewline(exampleCode)) }) + }], { showCode: false, shorthand: sliceQueryShorthand([criterion], escapeNewline(exampleCode)) }) } In this simple scenario, the _lineage_ is equivalent to the slice (and in-fact the complete code). @@ -264,18 +264,18 @@ registerQueryDocumentation('resolve-value', { functionName: executeSearch.name, functionFile: '../queries/catalog/resolve-value-query/resolve-value-query-executor.ts', buildExplanation: async(shell: RShell) => { - const exampleCode = 'x <- 1\nprint(x)'; - const criteria = ['2@x'] as SlicingCriteria; + const exampleCode = 'x <- 1\ny <-2\nprint(x)\nprint(y)'; + const criteria = ['3@x', '4@y'] as SlicingCriteria; 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 [Interface](${FlowrWikiBaseRef}/Interface) wiki page for more information). -Using the example code \`${exampleCode}\` (with the \`print(x)\` in the second line), the following query returns all values of \`x\` in the code: +Using the example code \`${exampleCode}\` (with newlines), the following query returns all values of \`x\` in the code: ${ await showQuery(shell, exampleCode, [{ type: 'resolve-value', criteria: criteria - }], { showCode: true, multipleCriteria: true, shorthand: sliceQueryShorthand(criteria[0], escapeNewline(exampleCode)) }) + }], { showCode: true, shorthand: sliceQueryShorthand(criteria, escapeNewline(exampleCode)) }) } `; } @@ -321,7 +321,7 @@ ${ await showQuery(shell, exampleCode, [{ type: 'origin', criterion: criterion - }], { showCode: true, shorthand: sliceQueryShorthand(criterion, escapeNewline(exampleCode)) }) + }], { showCode: true, shorthand: sliceQueryShorthand([criterion], escapeNewline(exampleCode)) }) } `; } @@ -453,7 +453,7 @@ ${ await showQuery(shell, exampleCode, [{ type: 'df-shape', criterion: criterion - }], { showCode: true, collapseQuery: true, shorthand: sliceQueryShorthand(criterion, escapeNewline(exampleCode)) }) + }], { showCode: true, collapseQuery: true, shorthand: sliceQueryShorthand([criterion], escapeNewline(exampleCode)) }) } `; } @@ -527,7 +527,8 @@ registerQueryDocumentation('static-slice', { functionName: executeStaticSliceQuery.name, functionFile: '../queries/catalog/static-slice-query/static-slice-query-executor.ts', buildExplanation: async(shell: RShell) => { - const exampleCode = 'x <- 1\ny <- 2\nx'; + const exampleCode = 'x <- 1\ny <- 2\nz <- 3\nx'; + const criteria = ['3@z','4@x'] as SlicingCriteria; 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). @@ -541,8 +542,8 @@ If you are interested in the parts required for the use of \`x\` in the last lin ${ await showQuery(shell, exampleCode, [{ type: 'static-slice', - criteria: ['3@x'] as SlicingCriteria - }], { showCode: false, multipleCriteria: true, shorthand: sliceQueryShorthand('3@x', escapeNewline(exampleCode)) }) + criteria: criteria + }], { showCode: false, shorthand: sliceQueryShorthand(criteria, escapeNewline(exampleCode)) }) } In general, you may be uninterested in seeing the reconstructed version and want to save some computation time, for this, @@ -552,7 +553,7 @@ ${ details('No Reconstruction Example', await showQuery(shell, exampleCode, [{ type: 'static-slice', - criteria: ['3@x'], + criteria: ['4@x'], noReconstruction: true }], { showCode: false }) ) @@ -565,7 +566,7 @@ ${ type: 'static-slice', criteria: ['1@x'], direction: SliceDirection.Forward - }], { showCode: false, multipleCriteria: true, shorthand: sliceQueryShorthand('1@x', escapeNewline(exampleCode), true) }) + }], { showCode: false, shorthand: sliceQueryShorthand(['1@x'], escapeNewline(exampleCode), true) }) } You can disable [magic comments](${FlowrWikiBaseRef}/Interface#slice-magic-comments) using the \`noMagicComments\` flag. @@ -747,7 +748,7 @@ registerQueryDocumentation('location-map', { files: [path.resolve('./src/util/range.ts')], }); const exampleCode = 'x + 1\nx * 2'; - const criteria = ['2@x'] as SlicingCriteria; + const criteria = ['1@x','2@x'] as SlicingCriteria; return ` A query like the ${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. @@ -770,7 +771,7 @@ ${ await showQuery(shell, exampleCode, [{ type: 'location-map', ids: criteria - }], { showCode: false, collapseQuery: true, multipleCriteria: true, shorthand: sliceQueryShorthand(criteria[0], escapeNewline(exampleCode)) }) + }], { showCode: false, collapseQuery: true, shorthand: sliceQueryShorthand(criteria, escapeNewline(exampleCode)) }) } All locations are given as a ${shortLink('SourceRange', types.info)} paired with the file id in the format \`[file-id, [start-line, start-column, end-line, end-column]]\`. From ba43376da0f747ead7aa4c6e4b82d6e08975ecc3 Mon Sep 17 00:00:00 2001 From: MaxAtoms <7847075+MaxAtoms@users.noreply.github.com> Date: Sun, 9 Nov 2025 19:17:48 +0100 Subject: [PATCH 17/17] lint-fix: adapt to new linting rules --- src/documentation/doc-util/doc-escape.ts | 1 - src/documentation/doc-util/doc-query.ts | 3 +++ src/documentation/print-query-wiki.ts | 6 +++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/documentation/doc-util/doc-escape.ts b/src/documentation/doc-util/doc-escape.ts index 65370bd3ee9..0e5086e3d43 100644 --- a/src/documentation/doc-util/doc-escape.ts +++ b/src/documentation/doc-util/doc-escape.ts @@ -19,7 +19,6 @@ export function escapeHTML(str: string | undefined): string | undefined { /** * Escapes newline characters in a string (Supports Windows and Unix newlines). - * * @param str - The string to escape * @returns The escaped string */ diff --git a/src/documentation/doc-util/doc-query.ts b/src/documentation/doc-util/doc-query.ts index 1ce8de26d0e..e589ef27dce 100644 --- a/src/documentation/doc-util/doc-query.ts +++ b/src/documentation/doc-util/doc-query.ts @@ -115,6 +115,9 @@ export function registerQueryDocumentation(query: SupportedQueryTypes | Supporte map.set(query, doc); } +/** + * Creates a REPL shorthand for the given slicing criteria and R code. + */ export function sliceQueryShorthand(criteria: SlicingCriteria, code: string, forward?: boolean) { return `(${(criteria.join(';'))})${forward ? 'f' : ''} "${code}"`; } diff --git a/src/documentation/print-query-wiki.ts b/src/documentation/print-query-wiki.ts index d38821bd461..2b3ae5c0f56 100644 --- a/src/documentation/print-query-wiki.ts +++ b/src/documentation/print-query-wiki.ts @@ -621,9 +621,9 @@ ${ await showQuery(shell, exampleCode, [{ type: 'linter', rules: ['file-path-validity'], - }], { - showCode: false, - collapseQuery: true, + }], { + showCode: false, + collapseQuery: true, shorthand: `rules:file-path-validity "${exampleCode}"` }) }