@eagleoutice/flowr 2.4.8 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,7 +24,7 @@ It offers a wide variety of features, for example:
24
24
 
25
25
  ```shell
26
26
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
27
- flowR repl using flowR v2.4.7, R v4.5.0 (r-shell engine)
27
+ flowR repl using flowR v2.4.8, R v4.5.0 (r-shell engine)
28
28
  R> :query @linter "read.csv(\"/root/x.txt\")"
29
29
  ```
30
30
 
@@ -78,34 +78,34 @@ It offers a wide variety of features, for example:
78
78
 
79
79
  _Results (prettified and summarized):_
80
80
 
81
- Query: **linter** (14 ms)\
81
+ Query: **linter** (15 ms)\
82
82
     ╰ **Deprecated Functions** (deprecated-functions):\
83
83
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalDeprecatedCalls":0,"totalDeprecatedFunctionDefinitions":0,"searchTimeMs":2,"processTimeMs":0}</code>\
84
84
  &nbsp;&nbsp;&nbsp;╰ **File Path Validity** (file-path-validity):\
85
85
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ certain:\
86
86
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ Path `/root/x.txt` at 1.1-23\
87
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalReads":1,"totalUnknown":0,"totalWritesBeforeAlways":0,"totalValid":0,"searchTimeMs":4,"processTimeMs":1}</code>\
87
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalReads":1,"totalUnknown":0,"totalWritesBeforeAlways":0,"totalValid":0,"searchTimeMs":5,"processTimeMs":0}</code>\
88
88
  &nbsp;&nbsp;&nbsp;╰ **Seeded Randomness** (seeded-randomness):\
89
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"consumerCalls":0,"callsWithFunctionProducers":0,"callsWithAssignmentProducers":0,"callsWithNonConstantProducers":0,"searchTimeMs":0,"processTimeMs":1}</code>\
89
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"consumerCalls":0,"callsWithFunctionProducers":0,"callsWithAssignmentProducers":0,"callsWithNonConstantProducers":0,"searchTimeMs":1,"processTimeMs":0}</code>\
90
90
  &nbsp;&nbsp;&nbsp;╰ **Absolute Paths** (absolute-file-paths):\
91
91
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ certain:\
92
92
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ Path `/root/x.txt` at 1.1-23\
93
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalConsidered":1,"totalUnknown":0,"searchTimeMs":1,"processTimeMs":1}</code>\
93
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalConsidered":1,"totalUnknown":0,"searchTimeMs":2,"processTimeMs":0}</code>\
94
94
  &nbsp;&nbsp;&nbsp;╰ **Unused Definitions** (unused-definitions):\
95
95
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalConsidered":0,"searchTimeMs":0,"processTimeMs":0}</code>\
96
96
  &nbsp;&nbsp;&nbsp;╰ **Naming Convention** (naming-convention):\
97
97
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"numMatches":0,"numBreak":0,"searchTimeMs":0,"processTimeMs":0}</code>\
98
98
  &nbsp;&nbsp;&nbsp;╰ **Dataframe Access Validation** (dataframe-access-validation):\
99
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"numOperations":0,"numAccesses":0,"totalAccessed":0,"searchTimeMs":0,"processTimeMs":2}</code>\
99
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"numOperations":0,"numAccesses":0,"totalAccessed":0,"searchTimeMs":0,"processTimeMs":4}</code>\
100
100
  &nbsp;&nbsp;&nbsp;╰ **Dead Code** (dead-code):\
101
101
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"consideredNodes":5,"searchTimeMs":1,"processTimeMs":0}</code>\
102
102
  &nbsp;&nbsp;&nbsp;╰ **Useless Loops** (useless-loop):\
103
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"numOfUselessLoops":0,"searchTimeMs":0,"processTimeMs":1}</code>\
104
- _All queries together required ≈14 ms (1ms accuracy, total 216 ms)_
103
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"numOfUselessLoops":0,"searchTimeMs":0,"processTimeMs":0}</code>\
104
+ _All queries together required ≈16 ms (1ms accuracy, total 209 ms)_
105
105
 
106
106
  <details> <summary style="color:gray">Show Detailed Results as Json</summary>
107
107
 
108
- The analysis required _215.9 ms_ (including parsing and normalization and the query) within the generation environment.
108
+ The analysis required _209.2 ms_ (including parsing and normalization and the query) within the generation environment.
109
109
 
110
110
  In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
111
111
  Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki/Interface) wiki page for more information on how to get those.
@@ -144,8 +144,8 @@ It offers a wide variety of features, for example:
144
144
  "totalUnknown": 0,
145
145
  "totalWritesBeforeAlways": 0,
146
146
  "totalValid": 0,
147
- "searchTimeMs": 4,
148
- "processTimeMs": 1
147
+ "searchTimeMs": 5,
148
+ "processTimeMs": 0
149
149
  }
150
150
  },
151
151
  "seeded-randomness": {
@@ -155,8 +155,8 @@ It offers a wide variety of features, for example:
155
155
  "callsWithFunctionProducers": 0,
156
156
  "callsWithAssignmentProducers": 0,
157
157
  "callsWithNonConstantProducers": 0,
158
- "searchTimeMs": 0,
159
- "processTimeMs": 1
158
+ "searchTimeMs": 1,
159
+ "processTimeMs": 0
160
160
  }
161
161
  },
162
162
  "absolute-file-paths": {
@@ -175,8 +175,8 @@ It offers a wide variety of features, for example:
175
175
  ".meta": {
176
176
  "totalConsidered": 1,
177
177
  "totalUnknown": 0,
178
- "searchTimeMs": 1,
179
- "processTimeMs": 1
178
+ "searchTimeMs": 2,
179
+ "processTimeMs": 0
180
180
  }
181
181
  },
182
182
  "unused-definitions": {
@@ -203,7 +203,7 @@ It offers a wide variety of features, for example:
203
203
  "numAccesses": 0,
204
204
  "totalAccessed": 0,
205
205
  "searchTimeMs": 0,
206
- "processTimeMs": 2
206
+ "processTimeMs": 4
207
207
  }
208
208
  },
209
209
  "dead-code": {
@@ -219,16 +219,16 @@ It offers a wide variety of features, for example:
219
219
  ".meta": {
220
220
  "numOfUselessLoops": 0,
221
221
  "searchTimeMs": 0,
222
- "processTimeMs": 1
222
+ "processTimeMs": 0
223
223
  }
224
224
  }
225
225
  },
226
226
  ".meta": {
227
- "timing": 14
227
+ "timing": 15
228
228
  }
229
229
  },
230
230
  ".meta": {
231
- "timing": 14
231
+ "timing": 16
232
232
  }
233
233
  }
234
234
  ```
@@ -295,7 +295,7 @@ It offers a wide variety of features, for example:
295
295
 
296
296
  ```shell
297
297
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
298
- flowR repl using flowR v2.4.7, R v4.5.0 (r-shell engine)
298
+ flowR repl using flowR v2.4.8, R v4.5.0 (r-shell engine)
299
299
  R> :slicer test/testfiles/example.R --criterion "11@sum"
300
300
  ```
301
301
 
@@ -378,7 +378,7 @@ It offers a wide variety of features, for example:
378
378
 
379
379
  ```shell
380
380
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
381
- flowR repl using flowR v2.4.7, R v4.5.0 (r-shell engine)
381
+ flowR repl using flowR v2.4.8, R v4.5.0 (r-shell engine)
382
382
  R> :dataflow* test/testfiles/example.R
383
383
  ```
384
384
 
@@ -683,7 +683,7 @@ It offers a wide variety of features, for example:
683
683
  ```
684
684
 
685
685
 
686
- (The analysis required _14.9 ms_ (including parse and normalize, using the [r-shell](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
686
+ (The analysis required _14.2 ms_ (including parse and normalize, using the [r-shell](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
687
687
 
688
688
 
689
689
 
@@ -728,6 +728,12 @@ You can enter <span title="Description (Repl Command): Show help information (al
728
728
 
729
729
  ![Example of a simple REPL session](wiki/gif/repl-demo-opt.gif)
730
730
 
731
+ If you want to use the same commands:
732
+
733
+ 1. First this runs `docker run -it --rm eagleoutice/flowr` in a terminal to start the REPL.
734
+ 2. In the REPL, it runs `:slicer -c '11@prod' demo.R --diff` to slice the example file `demo.R` for the print statement in line 11.
735
+ Please note that the `11` refers to the 11th line number to slice for!
736
+
731
737
  </details>
732
738
 
733
739
  ## 📜 More Information
@@ -9,7 +9,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.BenchmarkSlicer = exports.benchmarkLogger = void 0;
11
11
  const stopwatch_1 = require("./stopwatch");
12
- const fs_1 = __importDefault(require("fs"));
13
12
  const seedrandom_1 = __importDefault(require("seedrandom"));
14
13
  const log_1 = require("../util/log");
15
14
  const assert_1 = require("../util/assert");
@@ -30,6 +29,7 @@ const extract_cfg_1 = require("../control-flow/extract-cfg");
30
29
  const absint_info_1 = require("../abstract-interpretation/data-frame/absint-info");
31
30
  const domain_1 = require("../abstract-interpretation/data-frame/domain");
32
31
  const shape_inference_1 = require("../abstract-interpretation/data-frame/shape-inference");
32
+ const fs_1 = __importDefault(require("fs"));
33
33
  /**
34
34
  * The logger to be used for benchmarking as a global object.
35
35
  */
@@ -19,7 +19,7 @@ function writeGraphOutput(ultimate, outputGraphPath) {
19
19
  name: pointName[0].toUpperCase() + pointName.slice(1),
20
20
  unit: 'ms',
21
21
  value: Number(measurement.mean / 1e6),
22
- range: Number(measurement.std / 1e6),
22
+ range: String(Number(measurement.std / 1e6)),
23
23
  extra: `median: ${(measurement.median / 1e6).toFixed(2)}ms`
24
24
  });
25
25
  }
@@ -51,7 +51,7 @@ function writeGraphOutput(ultimate, outputGraphPath) {
51
51
  name: 'memory (df-graph)',
52
52
  unit: 'KiB',
53
53
  value: ultimate.dataflow.sizeOfObject.mean / 1024,
54
- range: ultimate.dataflow.sizeOfObject.std / 1024,
54
+ range: String(ultimate.dataflow.sizeOfObject.std / 1024),
55
55
  extra: `median: ${(ultimate.dataflow.sizeOfObject.median / 1024).toFixed(2)}`
56
56
  });
57
57
  // write the output file
package/cli/slicer-app.js CHANGED
@@ -15,6 +15,7 @@ const print_1 = require("../benchmark/stats/print");
15
15
  const magic_comments_1 = require("../reconstruct/auto-select/magic-comments");
16
16
  const auto_select_defaults_1 = require("../reconstruct/auto-select/auto-select-defaults");
17
17
  const config_1 = require("../config");
18
+ const adapter_1 = require("../util/formats/adapter");
18
19
  const options = (0, script_1.processCommandLineArgs)('slicer', ['input', 'criterion'], {
19
20
  subtitle: 'Slice R code based on a given slicing criterion',
20
21
  examples: [
@@ -32,7 +33,7 @@ async function getSlice() {
32
33
  const config = (0, config_1.getConfig)();
33
34
  await slicer.init(options['input-is-text']
34
35
  ? { request: 'text', content: options.input.replaceAll('\\n', '\n') }
35
- : { request: 'file', content: options.input }, config, options['no-magic-comments'] ? auto_select_defaults_1.doNotAutoSelect : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.doNotAutoSelect));
36
+ : (0, adapter_1.requestFromFile)(options.input), config, options['no-magic-comments'] ? auto_select_defaults_1.doNotAutoSelect : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.doNotAutoSelect));
36
37
  let mappedSlices = [];
37
38
  let reconstruct = undefined;
38
39
  const doSlicing = options.criterion.trim() !== '';
@@ -74,7 +75,11 @@ async function getSlice() {
74
75
  }
75
76
  else {
76
77
  if (doSlicing && options.diff) {
77
- const originalCode = options['input-is-text'] ? options.input : fs_1.default.readFileSync(options.input).toString();
78
+ let originalCode = options.input;
79
+ if (!options['input-is-text']) {
80
+ const request = (0, adapter_1.requestFromFile)(options.input);
81
+ originalCode = request.request === 'text' ? request.content : fs_1.default.readFileSync(request.content).toString();
82
+ }
78
83
  console.log((0, slice_diff_ansi_1.sliceDiffAnsi)(slice.result, normalize, new Set(mappedSlices.map(({ id }) => id)), originalCode));
79
84
  }
80
85
  if (options.stats) {
@@ -201,6 +201,10 @@ To get started, install the [vitest Extension](https://marketplace.visualstudio.
201
201
  #### Webstorm
202
202
 
203
203
  Please follow the official guide [here](https://www.jetbrains.com/help/webstorm/vitest.html).
204
+ Note that the working directory has to be set to the project root directory, not the test subdirectory!
205
+ Otherwise, the tests will not be instantiated.
206
+
207
+ ![Webstorm test configuration](img/testing-webstorm.png)
204
208
 
205
209
  <a id='ci-pipeline'></a>
206
210
  ## 🪈 CI Pipeline
@@ -142,6 +142,12 @@ You can enter ${(0, doc_cli_option_1.getReplCommand)('help')} to gain more infor
142
142
 
143
143
  ![Example of a simple REPL session](wiki/gif/repl-demo-opt.gif)
144
144
 
145
+ If you want to use the same commands:
146
+
147
+ 1. First this runs \`docker run -it --rm eagleoutice/flowr\` in a terminal to start the REPL.
148
+ 2. In the REPL, it runs \`:slicer -c '11@prod' demo.R --diff\` to slice the example file \`demo.R\` for the print statement in line 11.
149
+ Please note that the \`11\` refers to the 11th line number to slice for!
150
+
145
151
  </details>
146
152
 
147
153
  ## 📜 More Information
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eagleoutice/flowr",
3
- "version": "2.4.8",
3
+ "version": "2.5.0",
4
4
  "description": "Static Dataflow Analyzer and Program Slicer for the R Programming Language",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "repository": {
@@ -183,6 +183,7 @@
183
183
  "@j-ulrich/release-it-regex-bumper": "^5.3.0",
184
184
  "@types/command-line-args": "^5.2.3",
185
185
  "@types/command-line-usage": "^5.0.4",
186
+ "@types/commonmark": "^0.27.10",
186
187
  "@types/n-readlines": "^1.0.6",
187
188
  "@types/n3": "^1.26.0",
188
189
  "@types/object-hash": "^3.0.6",
@@ -212,6 +213,8 @@
212
213
  "clipboardy": "^4.0.0",
213
214
  "command-line-args": "^6.0.1",
214
215
  "command-line-usage": "^7.0.3",
216
+ "commonmark": "^0.31.2",
217
+ "gray-matter": "^4.0.3",
215
218
  "joi": "^18.0.1",
216
219
  "lz-string": "^1.5.0",
217
220
  "n-readlines": "^1.0.1",
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.TreeSitterExecutor = exports.DEFAULT_TREE_SITTER_WASM_PATH = exports.DEFAULT_TREE_SITTER_R_WASM_PATH = void 0;
7
7
  const web_tree_sitter_1 = __importDefault(require("web-tree-sitter"));
8
- const fs_1 = __importDefault(require("fs"));
9
8
  const log_1 = require("../../../util/log");
9
+ const fs_1 = __importDefault(require("fs"));
10
10
  exports.DEFAULT_TREE_SITTER_R_WASM_PATH = './node_modules/@eagleoutice/tree-sitter-r/tree-sitter-r.wasm';
11
11
  exports.DEFAULT_TREE_SITTER_WASM_PATH = './node_modules/web-tree-sitter/tree-sitter.wasm';
12
12
  const wasmLog = log_1.log.getSubLogger({ name: 'tree-sitter-wasm' });
@@ -2,16 +2,24 @@ import { type RShell } from './shell';
2
2
  import type { AsyncOrSync } from 'ts-essentials';
3
3
  import { RShellExecutor } from './shell-executor';
4
4
  import type { NormalizedAst } from './lang-4.x/ast/model/processing/decorate';
5
+ import type { SupportedFormats } from '../util/formats/adapter-format';
5
6
  export declare const fileProtocol = "file://";
6
- export interface RParseRequestFromFile {
7
+ export interface PraseRequestAdditionalInfoBase {
8
+ type: SupportedFormats;
9
+ }
10
+ export interface RParseRequestFromFile<AdditionalInfo extends PraseRequestAdditionalInfoBase = PraseRequestAdditionalInfoBase> {
7
11
  readonly request: 'file';
8
12
  /**
9
13
  * The path to the file (an absolute path is probably best here).
10
14
  * See {@link RParseRequests} for multiple files.
11
15
  */
12
16
  readonly content: string;
17
+ /**
18
+ * Aditional info from different file formates like .Rmd
19
+ */
20
+ readonly info?: AdditionalInfo;
13
21
  }
14
- export interface RParseRequestFromText {
22
+ export interface RParseRequestFromText<AdditionalInfo extends PraseRequestAdditionalInfoBase = PraseRequestAdditionalInfoBase> {
15
23
  readonly request: 'text';
16
24
  /**
17
25
  * Source code to parse (not a file path).
@@ -20,6 +28,10 @@ export interface RParseRequestFromText {
20
28
  * or concatenate their contents to pass them with this request.
21
29
  */
22
30
  readonly content: string;
31
+ /**
32
+ * Aditional info from different file formates like .Rmd
33
+ */
34
+ readonly info?: AdditionalInfo;
23
35
  }
24
36
  /**
25
37
  * A provider for an {@link RParseRequests} that can be used, for example, to override source file parsing behavior in tests
@@ -22,6 +22,7 @@ const decorate_1 = require("./lang-4.x/ast/model/processing/decorate");
22
22
  const type_1 = require("./lang-4.x/ast/model/type");
23
23
  const fs_1 = __importDefault(require("fs"));
24
24
  const path_1 = __importDefault(require("path"));
25
+ const adapter_1 = require("../util/formats/adapter");
25
26
  exports.fileProtocol = 'file://';
26
27
  /**
27
28
  * Creates a {@link RParseRequests} from a given input.
@@ -35,10 +36,15 @@ function requestFromInput(input) {
35
36
  }
36
37
  const content = input;
37
38
  const file = content.startsWith(exports.fileProtocol);
38
- return {
39
- request: file ? 'file' : 'text',
40
- content: file ? content.slice(7) : content
41
- };
39
+ if (file) {
40
+ return (0, adapter_1.requestFromFile)(content.slice(7));
41
+ }
42
+ else {
43
+ return {
44
+ request: 'text',
45
+ content: content
46
+ };
47
+ }
42
48
  }
43
49
  function requestProviderFromFile() {
44
50
  return {
@@ -0,0 +1,6 @@
1
+ import type { RParseRequest } from '../../r-bridge/retriever';
2
+ export interface FileAdapter {
3
+ convertRequest(request: RParseRequest): RParseRequest;
4
+ }
5
+ export type SupportedFormats = 'R' | 'Rmd';
6
+ export type SupportedDocumentTypes = '.r' | '.rmd';
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=adapter-format.js.map
@@ -0,0 +1,16 @@
1
+ import type { RParseRequest } from '../../r-bridge/retriever';
2
+ export declare const FileAdapters: {
3
+ readonly R: {
4
+ convertRequest: (request: RParseRequest) => RParseRequest;
5
+ };
6
+ readonly Rmd: {
7
+ convertRequest: (request: RParseRequest) => import("../../r-bridge/retriever").RParseRequestFromText<import("./adapters/rmd-adapter").RmdInfo>;
8
+ };
9
+ };
10
+ export declare const DocumentTypeToFormat: {
11
+ readonly '.r': "R";
12
+ readonly '.rmd': "Rmd";
13
+ };
14
+ export type AdapterReturnTypes = ReturnType<typeof FileAdapters[keyof typeof FileAdapters]['convertRequest']>;
15
+ export declare function requestFromFile(path: string): AdapterReturnTypes;
16
+ export declare function inferFileType(request: RParseRequest): keyof typeof FileAdapters;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DocumentTypeToFormat = exports.FileAdapters = void 0;
7
+ exports.requestFromFile = requestFromFile;
8
+ exports.inferFileType = inferFileType;
9
+ const r_adapter_1 = require("./adapters/r-adapter");
10
+ const path_1 = __importDefault(require("path"));
11
+ const rmd_adapter_1 = require("./adapters/rmd-adapter");
12
+ exports.FileAdapters = {
13
+ 'R': r_adapter_1.RAdapter,
14
+ 'Rmd': rmd_adapter_1.RmdAdapter
15
+ };
16
+ exports.DocumentTypeToFormat = {
17
+ '.r': 'R',
18
+ '.rmd': 'Rmd'
19
+ };
20
+ function requestFromFile(path) {
21
+ const baseRequest = {
22
+ request: 'file',
23
+ content: path
24
+ };
25
+ const type = inferFileType(baseRequest);
26
+ return exports.FileAdapters[type].convertRequest(baseRequest);
27
+ }
28
+ function inferFileType(request) {
29
+ if (request.request === 'text') {
30
+ // For now we don't know what type the request is
31
+ // and have to assume it is normal R Code
32
+ // In the future we could add a heuristic to guess the type
33
+ return 'R';
34
+ }
35
+ const type = path_1.default.extname(request.content).toLowerCase();
36
+ // Fallback to default if unknown
37
+ if (!Object.hasOwn(exports.DocumentTypeToFormat, type)) {
38
+ return 'R';
39
+ }
40
+ return exports.DocumentTypeToFormat[type];
41
+ }
42
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1,4 @@
1
+ import type { RParseRequest } from '../../../r-bridge/retriever';
2
+ export declare const RAdapter: {
3
+ convertRequest: (request: RParseRequest) => RParseRequest;
4
+ };
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RAdapter = void 0;
4
+ exports.RAdapter = {
5
+ convertRequest: (request) => request
6
+ };
7
+ //# sourceMappingURL=r-adapter.js.map
@@ -0,0 +1,26 @@
1
+ import type { Node } from 'commonmark';
2
+ import type { RParseRequest, RParseRequestFromText } from '../../../r-bridge/retriever';
3
+ export interface CodeBlock {
4
+ options: string;
5
+ code: string;
6
+ }
7
+ export type CodeBlockEx = CodeBlock & {
8
+ startpos: {
9
+ line: number;
10
+ col: number;
11
+ };
12
+ };
13
+ export interface RmdInfo {
14
+ type: 'Rmd';
15
+ blocks: CodeBlock[];
16
+ options: object;
17
+ }
18
+ export declare const RmdAdapter: {
19
+ convertRequest: (request: RParseRequest) => RParseRequestFromText<RmdInfo>;
20
+ };
21
+ export declare function isRCodeBlock(node: Node): node is Node & {
22
+ literal: string;
23
+ info: string;
24
+ };
25
+ export declare function restoreBlocksWithoutMd(blocks: CodeBlockEx[], totalLines: number): string;
26
+ export declare function parseCodeBlockOptions(header: string, content: string): string;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RmdAdapter = void 0;
7
+ exports.isRCodeBlock = isRCodeBlock;
8
+ exports.restoreBlocksWithoutMd = restoreBlocksWithoutMd;
9
+ exports.parseCodeBlockOptions = parseCodeBlockOptions;
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const commonmark_1 = require("commonmark");
12
+ const gray_matter_1 = __importDefault(require("gray-matter"));
13
+ const assert_1 = require("../../assert");
14
+ exports.RmdAdapter = {
15
+ convertRequest: (request) => {
16
+ // Read and Parse Markdown
17
+ const raw = request.request === 'text'
18
+ ? request.content
19
+ : fs_1.default.readFileSync(request.content, 'utf-8').toString();
20
+ const parser = new commonmark_1.Parser();
21
+ const ast = parser.parse(raw);
22
+ // Parse Frontmatter
23
+ const frontmatter = (0, gray_matter_1.default)(raw);
24
+ // Parse Codeblocks
25
+ const walker = ast.walker();
26
+ const blocks = [];
27
+ let e;
28
+ while ((e = walker.next())) {
29
+ const node = e.node;
30
+ if (!isRCodeBlock(node)) {
31
+ continue;
32
+ }
33
+ blocks.push({
34
+ code: node.literal,
35
+ options: parseCodeBlockOptions(node.info, node.literal),
36
+ startpos: { line: node.sourcepos[0][0] + 1, col: 0 }
37
+ });
38
+ }
39
+ return {
40
+ request: 'text',
41
+ content: restoreBlocksWithoutMd(blocks, countNewlines(raw)),
42
+ info: {
43
+ // eslint-disable-next-line unused-imports/no-unused-vars
44
+ blocks: blocks.map(({ startpos, ...block }) => block),
45
+ options: frontmatter.data,
46
+ type: 'Rmd'
47
+ }
48
+ };
49
+ }
50
+ };
51
+ const RTagRegex = /{[rR](?:[\s,][^}]*)?}/;
52
+ function isRCodeBlock(node) {
53
+ return node.type === 'code_block' && node.literal !== null && node.info !== null && RTagRegex.test(node.info);
54
+ }
55
+ const LineRegex = /\r\n|\r|\n/;
56
+ function countNewlines(str) {
57
+ return str.split(LineRegex).length - 1;
58
+ }
59
+ function restoreBlocksWithoutMd(blocks, totalLines) {
60
+ let line = 1;
61
+ let output = '';
62
+ const goToLine = (n) => {
63
+ const diff = n - line;
64
+ (0, assert_1.guard)(diff >= 0);
65
+ line += diff;
66
+ output += '\n'.repeat(diff);
67
+ };
68
+ for (const block of blocks) {
69
+ goToLine(block.startpos.line);
70
+ output += block.code;
71
+ line += countNewlines(block.code);
72
+ }
73
+ // Add remainder of file
74
+ goToLine(totalLines + 1);
75
+ return output;
76
+ }
77
+ function parseCodeBlockOptions(header, content) {
78
+ let opts = header.length === 3 // '{r}' => header.length=3 (no options in header)
79
+ ? ''
80
+ : header.substring(3, header.length - 1).trim();
81
+ const lines = content.split('\n');
82
+ for (const line of lines) {
83
+ if (!line.trim().startsWith('#|')) {
84
+ break;
85
+ }
86
+ const opt = line.substring(3);
87
+ opts += opts.length === 0 ? opt : `, ${opt}`;
88
+ }
89
+ return opts;
90
+ }
91
+ //# sourceMappingURL=rmd-adapter.js.map
package/util/version.js CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.flowrVersion = flowrVersion;
4
4
  const semver_1 = require("semver");
5
5
  // this is automatically replaced with the current version by release-it
6
- const version = '2.4.8';
6
+ const version = '2.5.0';
7
7
  function flowrVersion() {
8
8
  return new semver_1.SemVer(version);
9
9
  }