@eagleoutice/flowr 2.8.2 → 2.8.3

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.
@@ -101,7 +101,7 @@ export declare const DefaultBuiltinConfig: [{
101
101
  readonly assumePrimitive: false;
102
102
  }, {
103
103
  readonly type: "function";
104
- readonly names: ["print", "message", "warning"];
104
+ readonly names: ["print", "message", "warning", "warn", "info"];
105
105
  readonly processor: "builtin:default";
106
106
  readonly config: {
107
107
  readonly returnsNthArgument: 0;
@@ -262,7 +262,7 @@ export declare const DefaultBuiltinConfig: [{
262
262
  readonly assumePrimitive: true;
263
263
  }, {
264
264
  readonly type: "function";
265
- readonly names: ["stop", "abort"];
265
+ readonly names: ["stop", "abort", "cli_abort", "throw", "stop_bad_type", "stop_bad_element_type", "stop_bad_element_length"];
266
266
  readonly processor: "builtin:default";
267
267
  readonly config: {
268
268
  readonly useAsProcessor: "builtin:stop";
@@ -129,7 +129,7 @@ exports.DefaultBuiltinConfig = [
129
129
  { type: 'function', names: ['lapply', 'sapply', 'vapply'], processor: 'builtin:apply', config: { indexOfFunction: 1, nameOfFunctionArgument: 'FUN' }, assumePrimitive: false },
130
130
  { type: 'function', names: ['Lapply', 'Sapply', 'Vapply'], processor: 'builtin:apply', config: { indexOfFunction: 1, nameOfFunctionArgument: 'FUN' }, assumePrimitive: false }, /* functool wrappers */
131
131
  { type: 'function', names: ['apply', 'tapply', 'Tapply'], processor: 'builtin:apply', config: { indexOfFunction: 2, nameOfFunctionArgument: 'FUN' }, assumePrimitive: false },
132
- { type: 'function', names: ['print', 'message', 'warning'], processor: 'builtin:default', config: { returnsNthArgument: 0, forceArgs: 'all', hasUnknownSideEffects: { type: 'link-to-last-call', callName: /^sink$/ } }, assumePrimitive: false },
132
+ { type: 'function', names: ['print', 'message', 'warning', 'warn', 'info'], processor: 'builtin:default', config: { returnsNthArgument: 0, forceArgs: 'all', hasUnknownSideEffects: { type: 'link-to-last-call', callName: /^sink$/ } }, assumePrimitive: false },
133
133
  // graphics base
134
134
  { type: 'function', names: exports.PlotCreate,
135
135
  processor: 'builtin:default',
@@ -232,7 +232,13 @@ exports.DefaultBuiltinConfig = [
232
232
  { type: 'function', names: ['cat'], processor: 'builtin:default', config: { forceArgs: 'all', hasUnknownSideEffects: { type: 'link-to-last-call', callName: /^sink$/ } }, assumePrimitive: false },
233
233
  { type: 'function', names: ['switch'], processor: 'builtin:default', config: { forceArgs: [true] }, assumePrimitive: false },
234
234
  { type: 'function', names: ['return'], processor: 'builtin:default', config: { returnsNthArgument: 0, cfg: 1 /* ExitPointType.Return */, useAsProcessor: 'builtin:return' }, assumePrimitive: true },
235
- { type: 'function', names: ['stop', 'abort'], processor: 'builtin:default', config: { useAsProcessor: 'builtin:stop', cfg: 4 /* ExitPointType.Error */, forceArgs: ['all'] }, assumePrimitive: false },
235
+ {
236
+ type: 'function',
237
+ names: ['stop', 'abort', 'cli_abort', 'throw', 'stop_bad_type', 'stop_bad_element_type', 'stop_bad_element_length'],
238
+ processor: 'builtin:default',
239
+ config: { useAsProcessor: 'builtin:stop', cfg: 4 /* ExitPointType.Error */, forceArgs: ['all'] },
240
+ assumePrimitive: false
241
+ },
236
242
  { type: 'function', names: ['try'], processor: 'builtin:try', config: { block: 'expr', handlers: {} }, assumePrimitive: true },
237
243
  { type: 'function', names: ['tryCatch', 'tryCatchLog'], processor: 'builtin:try', config: { block: 'expr', handlers: { error: 'error', finally: 'finally' } }, assumePrimitive: true },
238
244
  { type: 'function', names: ['stopifnot'], processor: 'builtin:stopifnot', config: {}, assumePrimitive: false },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eagleoutice/flowr",
3
- "version": "2.8.2",
3
+ "version": "2.8.3",
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": {
@@ -4,6 +4,8 @@ export interface NamespaceInfo {
4
4
  exportedSymbols: string[];
5
5
  exportedFunctions: string[];
6
6
  exportS3Generics: Map<string, string[]>;
7
+ exportedPatterns: string[];
8
+ importedPackages: Map<string, string[] | 'all'>;
7
9
  loadsWithSideEffects: boolean;
8
10
  }
9
11
  export interface NamespaceFormat {
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FlowrNamespaceFile = void 0;
4
4
  const flowr_file_1 = require("../../../context/flowr-file");
5
+ const resolve_args_1 = require("../../../../abstract-interpretation/data-frame/resolve-args");
5
6
  /**
6
7
  * This decorates a text file and provides access to its content in the {@link NamespaceFormat}.
7
8
  */
@@ -43,6 +44,8 @@ function parseNamespace(file) {
43
44
  exportedSymbols: [],
44
45
  exportedFunctions: [],
45
46
  exportS3Generics: new Map(),
47
+ exportedPatterns: [],
48
+ importedPackages: new Map(),
46
49
  loadsWithSideEffects: false,
47
50
  },
48
51
  };
@@ -89,12 +92,37 @@ function parseNamespace(file) {
89
92
  exportedSymbols: [],
90
93
  exportedFunctions: [],
91
94
  exportS3Generics: new Map(),
95
+ exportedPatterns: [],
96
+ importedPackages: new Map(),
92
97
  loadsWithSideEffects: false,
93
98
  };
94
99
  }
95
100
  result[pkg].loadsWithSideEffects = true;
96
101
  break;
97
102
  }
103
+ case 'import': {
104
+ const pkg = args.trim();
105
+ result.current.importedPackages?.set(pkg, 'all');
106
+ break;
107
+ }
108
+ case 'importFrom': {
109
+ const parts = args.split(',').map(s => s.trim());
110
+ if (parts.length < 2) {
111
+ continue;
112
+ }
113
+ const [pkg, ...symbols] = parts;
114
+ let arr = result.current.importedPackages?.get(pkg);
115
+ if (!arr || arr === 'all') {
116
+ arr = [];
117
+ result.current.importedPackages?.set(pkg, arr);
118
+ }
119
+ arr.push(...symbols);
120
+ break;
121
+ }
122
+ case 'exportPattern': {
123
+ result.current.exportedPatterns?.push((0, resolve_args_1.unquoteArgument)(args.trim()));
124
+ break;
125
+ }
98
126
  }
99
127
  }
100
128
  return result;
@@ -57,6 +57,7 @@ class DefaultFlowrAnalyzerProjectDiscoveryPlugin extends FlowrAnalyzerProjectDis
57
57
  const requests = [];
58
58
  /* the dummy approach of collecting all files, group R and Rmd files, and be done with it */
59
59
  for (const file of (0, files_1.getAllFilesSync)(args.content, /.*/, this.ignorePathsRegex)) {
60
+ console.log(`Discovered file: ${file}`);
60
61
  const relativePath = path_1.default.relative(args.content, file);
61
62
  if (this.supportedExtensions.test(relativePath) && (!this.onlyTraversePaths || this.onlyTraversePaths.test(relativePath)) && !this.excludePathsRegex.test((0, built_in_source_1.platformDirname)(relativePath))) {
62
63
  requests.push({ content: file, request: 'file' });
@@ -28,10 +28,14 @@ exports.WriteFunctions = [
28
28
  }
29
29
  },
30
30
  // write functions that don't have argIndex are assumed to write to stdout
31
- { package: 'base', name: 'print', linkTo: OutputRedirects, resolveValue: true },
31
+ { package: 'base', name: 'print', linkTo: OutputRedirects, resolveValue: false },
32
32
  { package: 'base', name: 'cat', linkTo: OutputRedirects, argName: 'file', resolveValue: true },
33
- { package: 'base', name: 'message', linkTo: OutputRedirects, resolveValue: true },
34
- { package: 'base', name: 'warning', linkTo: OutputRedirects, resolveValue: true },
33
+ { package: 'base', name: 'message', linkTo: OutputRedirects, resolveValue: false },
34
+ { package: 'base', name: 'warning', linkTo: OutputRedirects, resolveValue: false },
35
+ { package: 'rlang', name: 'warn', linkTo: OutputRedirects, resolveValue: false },
36
+ { package: 'rlang', name: 'info', linkTo: OutputRedirects, resolveValue: false },
37
+ { package: 'cli', name: 'cli_warn', linkTo: OutputRedirects, resolveValue: false },
38
+ { package: 'cli', name: 'cli_abort', linkTo: OutputRedirects, resolveValue: false },
35
39
  { package: 'base', name: 'writeLines', argIdx: 1, argName: 'con', resolveValue: true },
36
40
  { package: 'base', name: 'writeChar', argIdx: 1, argName: 'con', resolveValue: true },
37
41
  { package: 'base', name: 'writeBin', argIdx: 1, argName: 'con', resolveValue: true },
@@ -0,0 +1,15 @@
1
+ import type { AstIdMap, ParentInformation } from '../lang-4.x/ast/model/processing/decorate';
2
+ import type { NodeId } from '../lang-4.x/ast/model/processing/node-id';
3
+ import type { RoxygenTag } from './roxygen-ast';
4
+ export interface DocumentationInfo {
5
+ doc?: Documentation;
6
+ }
7
+ export type Documentation = RoxygenTag | readonly RoxygenTag[];
8
+ /**
9
+ * Given a normalized AST and a node ID, returns the Roxygen documentation (if any) associated with that node.
10
+ * Please note that this does more than {@link parseRoxygenCommentsOfNode}, as it also traverses up the AST to find documentation.
11
+ * Additionally, this function instruments the normalized AST to cache the parsed documentation for future queries.
12
+ * @param idMap - The AST ID map to use for looking up nodes and traversing the AST.
13
+ * @param nodeId - The ID of the node to get documentation for.
14
+ */
15
+ export declare function getDocumentationOf(nodeId: NodeId, idMap: AstIdMap<ParentInformation & DocumentationInfo>): Documentation | undefined;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDocumentationOf = getDocumentationOf;
4
+ const roxygen_ast_1 = require("./roxygen-ast");
5
+ const type_1 = require("../lang-4.x/ast/model/type");
6
+ const roxygen_parse_1 = require("./roxygen-parse");
7
+ const CommentRetriever = {
8
+ [type_1.RType.Comment]: n => (0, roxygen_parse_1.parseRoxygenComment)([n.lexeme]),
9
+ [type_1.RType.Parameter]: (n, idMap) => {
10
+ // get the documentation of the parent function
11
+ const doc = n.info.parent ? getDocumentationOf(n.info.parent, idMap) : undefined;
12
+ const paramName = n.lexeme;
13
+ if (doc && paramName) {
14
+ if (Array.isArray(doc)) {
15
+ const res = doc.filter(t => t.type === roxygen_ast_1.KnownRoxygenTags.Param && t.value.name === paramName);
16
+ if (res.length === 1) {
17
+ return res[0];
18
+ }
19
+ else {
20
+ return res;
21
+ }
22
+ }
23
+ else {
24
+ if (doc.type === roxygen_ast_1.KnownRoxygenTags.Param && doc.value.name === paramName) {
25
+ return doc;
26
+ }
27
+ }
28
+ }
29
+ return undefined;
30
+ }
31
+ };
32
+ /**
33
+ * Given a normalized AST and a node ID, returns the Roxygen documentation (if any) associated with that node.
34
+ * Please note that this does more than {@link parseRoxygenCommentsOfNode}, as it also traverses up the AST to find documentation.
35
+ * Additionally, this function instruments the normalized AST to cache the parsed documentation for future queries.
36
+ * @param idMap - The AST ID map to use for looking up nodes and traversing the AST.
37
+ * @param nodeId - The ID of the node to get documentation for.
38
+ */
39
+ function getDocumentationOf(nodeId, idMap) {
40
+ const node = idMap.get(nodeId);
41
+ if (!node) {
42
+ return undefined;
43
+ }
44
+ else if (node.info.doc) {
45
+ return node.info.doc;
46
+ }
47
+ const retriever = CommentRetriever[node.type] ?? ((c, a) => (0, roxygen_parse_1.parseRoxygenCommentsOfNode)(c, a)?.tags);
48
+ const doc = retriever(node, idMap);
49
+ if (doc) {
50
+ // cache the documentation for future queries
51
+ const expanded = expandInheritsOfTags(doc, idMap);
52
+ node.info.doc = expanded;
53
+ return expanded;
54
+ }
55
+ return doc;
56
+ }
57
+ function expandInheritsOfTags(tags, idMap) {
58
+ const expandedTags = [];
59
+ const tagArray = Array.isArray(tags) ? tags : [tags];
60
+ for (const tag of tagArray) {
61
+ const expanded = expandInheritOfTag(tag, tagArray, idMap);
62
+ if (!expanded) {
63
+ continue;
64
+ }
65
+ if (Array.isArray(expanded)) {
66
+ expandedTags.push(...expanded);
67
+ }
68
+ else {
69
+ expandedTags.push(expanded);
70
+ }
71
+ }
72
+ if (expandedTags.length === 1) {
73
+ return expandedTags[0];
74
+ }
75
+ return expandedTags;
76
+ }
77
+ function getDocumentationOfByName(name, idMap) {
78
+ for (const [, node] of idMap) {
79
+ const nodeName = node.lexeme ?? node.info.fullLexeme;
80
+ if (nodeName !== name) {
81
+ continue;
82
+ }
83
+ return getDocumentationOf(node.info.id, idMap);
84
+ }
85
+ }
86
+ function filterDocumentationForParams(doc, filter) {
87
+ if (!doc) {
88
+ return doc;
89
+ }
90
+ if (Array.isArray(doc)) {
91
+ return doc.filter(filter);
92
+ }
93
+ else {
94
+ return filter(doc) ? doc : undefined;
95
+ }
96
+ }
97
+ function expandInheritOfTag(tag, otherTags, idMap) {
98
+ if (tag.type === roxygen_ast_1.KnownRoxygenTags.Inherit) {
99
+ const inheritDoc = getDocumentationOfByName(tag.value.source, idMap);
100
+ return filterDocumentationForParams(inheritDoc, t => tag.value.components.includes(t.type));
101
+ }
102
+ else if (tag.type === roxygen_ast_1.KnownRoxygenTags.InheritDotParams) {
103
+ const inheritDoc = getDocumentationOfByName(tag.value.source, idMap);
104
+ return filterDocumentationForParams(inheritDoc, t => t.type === roxygen_ast_1.KnownRoxygenTags.Param && t.value.name === '...');
105
+ }
106
+ else if (tag.type === roxygen_ast_1.KnownRoxygenTags.InheritParams) {
107
+ const inheritDoc = getDocumentationOfByName(tag.value, idMap);
108
+ const alreadyExplainedParams = new Set(otherTags.filter(t => t.type === roxygen_ast_1.KnownRoxygenTags.Param).map(t => t.value.name));
109
+ return filterDocumentationForParams(inheritDoc, t => t.type === roxygen_ast_1.KnownRoxygenTags.Param && !alreadyExplainedParams.has(t.value.name));
110
+ }
111
+ return tag;
112
+ }
113
+ //# sourceMappingURL=documentation-provider.js.map
@@ -4,6 +4,8 @@ import type { AstIdMap, ParentInformation } from '../lang-4.x/ast/model/processi
4
4
  /**
5
5
  * Parses the roxygen comments attached to a node into a RoxygenBlock AST node.
6
6
  * Will return `undefined` if there are no valid roxygen comments attached to the node.
7
+ * Please note that this does *not* do any clever mapping of parameters or requests.
8
+ * For a higher-level function that also traverses up the AST to find comments attached to parent nodes, see {@link getDocumentationOf}.
7
9
  * @param node - The node to parse the roxygen comments for
8
10
  * @param idMap - An optional id map to traverse up the AST to find comments attached to parent nodes
9
11
  */
@@ -26,6 +26,8 @@ function prepareCommentContext(commentText) {
26
26
  /**
27
27
  * Parses the roxygen comments attached to a node into a RoxygenBlock AST node.
28
28
  * Will return `undefined` if there are no valid roxygen comments attached to the node.
29
+ * Please note that this does *not* do any clever mapping of parameters or requests.
30
+ * For a higher-level function that also traverses up the AST to find comments attached to parent nodes, see {@link getDocumentationOf}.
29
31
  * @param node - The node to parse the roxygen comments for
30
32
  * @param idMap - An optional id map to traverse up the AST to find comments attached to parent nodes
31
33
  */
package/util/version.js CHANGED
@@ -6,7 +6,7 @@ exports.printVersionInformation = printVersionInformation;
6
6
  const semver_1 = require("semver");
7
7
  const assert_1 = require("./assert");
8
8
  // this is automatically replaced with the current version by release-it
9
- const version = '2.8.2';
9
+ const version = '2.8.3';
10
10
  /**
11
11
  * Retrieves the current flowR version as a new {@link SemVer} object.
12
12
  */