@eagleoutice/flowr 2.8.11 → 2.8.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eagleoutice/flowr",
3
- "version": "2.8.11",
3
+ "version": "2.8.12",
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": {
@@ -6,6 +6,10 @@ import { Package, type PackageType } from '../../package-version-plugins/package
6
6
  export type DCF = Map<string, string[]>;
7
7
  /**
8
8
  * This decorates a text file and provides access to its content as a DCF (Debian Control File)-like structure.
9
+ * Please use the static {@link FlowrDescriptionFile.from} method to create instances of this class.
10
+ * To access description specific fields, use the provided methods like {@link license}, {@link authors}, {@link suggests}, and {@link collate}.
11
+ * These methods parse and return the relevant information in structured formats.
12
+ * To access raw fields, use the {@link content} method inherited from {@link FlowrFile}.
9
13
  */
10
14
  export declare class FlowrDescriptionFile extends FlowrFile<DeepReadonly<DCF>> {
11
15
  private readonly wrapped;
@@ -31,7 +35,22 @@ export declare class FlowrDescriptionFile extends FlowrFile<DeepReadonly<DCF>> {
31
35
  * Returns the parsed authors from the `Authors@R` field in the DESCRIPTION file.
32
36
  */
33
37
  authors(): RAuthorInfo[] | undefined;
38
+ /**
39
+ * Returns the parsed suggested packages from the 'Suggests' field in the DESCRIPTION file.
40
+ */
34
41
  suggests(): Package[] | undefined;
42
+ /**
43
+ * Returns the 'Collate' field from the DESCRIPTION file.
44
+ */
45
+ collate(): readonly string[] | undefined;
46
+ /**
47
+ * Returns the parsed dependencies from the 'Depends' field in the DESCRIPTION file.
48
+ */
49
+ depends(): readonly Package[] | undefined;
50
+ /**
51
+ * Returns the parsed imports from the 'Imports' field in the DESCRIPTION file.
52
+ */
53
+ imports(): readonly Package[] | undefined;
35
54
  }
36
55
  /**
37
56
  * Parses the 'License' field from an R DESCRIPTION file into SPDX license expressions.
@@ -8,8 +8,13 @@ const r_author_1 = require("../../../../util/r-author");
8
8
  const args_1 = require("../../../../util/text/args");
9
9
  const r_license_1 = require("../../../../util/r-license");
10
10
  const package_1 = require("../../package-version-plugins/package");
11
+ const retriever_1 = require("../../../../r-bridge/retriever");
11
12
  /**
12
13
  * This decorates a text file and provides access to its content as a DCF (Debian Control File)-like structure.
14
+ * Please use the static {@link FlowrDescriptionFile.from} method to create instances of this class.
15
+ * To access description specific fields, use the provided methods like {@link license}, {@link authors}, {@link suggests}, and {@link collate}.
16
+ * These methods parse and return the relevant information in structured formats.
17
+ * To access raw fields, use the {@link content} method inherited from {@link FlowrFile}.
13
18
  */
14
19
  class FlowrDescriptionFile extends flowr_file_1.FlowrFile {
15
20
  wrapped;
@@ -59,10 +64,35 @@ class FlowrDescriptionFile extends flowr_file_1.FlowrFile {
59
64
  const parsedAuthors = authors?.flatMap(a => (0, r_author_1.parseTextualAuthorString)(a, [r_author_1.AuthorRole.Author])) ?? [];
60
65
  return parsedAuthors.concat(this.content().get('Maintainer')?.flatMap(m => (0, r_author_1.parseTextualAuthorString)(m, [r_author_1.AuthorRole.Creator])) ?? []);
61
66
  }
67
+ /**
68
+ * Returns the parsed suggested packages from the 'Suggests' field in the DESCRIPTION file.
69
+ */
62
70
  suggests() {
63
71
  const suggests = this.content().get('Suggests');
64
72
  return suggests ? parsePackagesWithVersions(suggests, 'package') : undefined;
65
73
  }
74
+ /**
75
+ * Returns the 'Collate' field from the DESCRIPTION file.
76
+ */
77
+ collate() {
78
+ const c = this.content().get('Collate');
79
+ // we join newlines, and then split quote sensitive:
80
+ return c ? (0, args_1.splitAtEscapeSensitive)(c.join(' '), true, ' ').map(s => (0, retriever_1.removeRQuotes)(s).trim()).filter(s => s.length > 0) : undefined;
81
+ }
82
+ /**
83
+ * Returns the parsed dependencies from the 'Depends' field in the DESCRIPTION file.
84
+ */
85
+ depends() {
86
+ const deps = this.content().get('Depends');
87
+ return deps ? parsePackagesWithVersions(deps, 'r') : undefined;
88
+ }
89
+ /**
90
+ * Returns the parsed imports from the 'Imports' field in the DESCRIPTION file.
91
+ */
92
+ imports() {
93
+ const imps = this.content().get('Imports');
94
+ return imps ? parsePackagesWithVersions(imps, 'package') : undefined;
95
+ }
66
96
  }
67
97
  exports.FlowrDescriptionFile = FlowrDescriptionFile;
68
98
  /**
@@ -117,25 +147,26 @@ function cleanValues(values) {
117
147
  .map(s => s.trim())
118
148
  .filter(s => s.length > 0);
119
149
  }
120
- const VersionRegex = /^([a-zA-Z0-9.]+)(?:\s*\(([><=~!]+)\s*([^)]+)\))?$/;
150
+ const VersionRegex = /([a-zA-Z0-9.]+)(?:\s*\(([><=~!]+)\s*([^)]+)\))?\s*/;
121
151
  /**
122
152
  * Parses package strings with optional version constraints into Package objects.
123
153
  * @param packageStrings - The package strings to parse
124
154
  * @param type - The type of the packages (e.g., 'r' or 'package')
125
155
  */
126
156
  function parsePackagesWithVersions(packageStrings, type) {
157
+ let str = packageStrings.join(' ');
158
+ let match;
127
159
  const packages = [];
128
- for (const entry of packageStrings) {
129
- const match = VersionRegex.exec(entry);
130
- if (match) {
131
- const [, name, operator, version] = match;
132
- const range = package_1.Package.parsePackageVersionRange(operator, version);
133
- packages.push(new package_1.Package({
134
- name: name,
135
- type: type,
136
- versionConstraints: range ? [range] : undefined
137
- }));
138
- }
160
+ // match until exhaustion
161
+ while ((match = VersionRegex.exec(str)) !== null) {
162
+ const [, name, operator, version] = match;
163
+ const range = package_1.Package.parsePackageVersionRange(operator, version);
164
+ packages.push(new package_1.Package({
165
+ name: name,
166
+ type: type,
167
+ versionConstraints: range ? [range] : undefined
168
+ }));
169
+ str = str.slice(match.index + match[0].length);
139
170
  }
140
171
  return packages;
141
172
  }
@@ -5,7 +5,6 @@ const flowr_analyzer_description_file_plugin_1 = require("../file-plugins/flowr-
5
5
  const semver_1 = require("semver");
6
6
  const flowr_analyzer_loading_order_plugin_1 = require("./flowr-analyzer-loading-order-plugin");
7
7
  const flowr_file_1 = require("../../context/flowr-file");
8
- const retriever_1 = require("../../../r-bridge/retriever");
9
8
  /**
10
9
  * This plugin extracts loading order information from R `DESCRIPTION` files.
11
10
  * It looks at the `Collate` field to determine the order in which files should be loaded.
@@ -25,10 +24,8 @@ class FlowrAnalyzerLoadingOrderDescriptionFilePlugin extends flowr_analyzer_load
25
24
  flowr_analyzer_description_file_plugin_1.descriptionFileLog.warn(`Found ${descFiles.length} description files, expected exactly one.`);
26
25
  }
27
26
  /** this will do the caching etc. for me */
28
- const deps = descFiles[0].content();
29
- if (deps.has('Collate')) {
30
- const collate = deps.get('Collate')?.map(f => (0, retriever_1.removeRQuotes)(f))
31
- ?? [];
27
+ const collate = descFiles[0].collate();
28
+ if (collate) {
32
29
  /* we probably have to do some more guesswork here */
33
30
  const unordered = ctx.files.loadingOrder.getUnorderedRequests();
34
31
  // sort them by their path index in the Collate field
@@ -5,7 +5,6 @@ const flowr_analyzer_package_versions_plugin_1 = require("./flowr-analyzer-packa
5
5
  const flowr_analyzer_description_file_plugin_1 = require("../file-plugins/flowr-analyzer-description-file-plugin");
6
6
  const semver_1 = require("semver");
7
7
  const flowr_file_1 = require("../../context/flowr-file");
8
- const flowr_description_file_1 = require("../file-plugins/files/flowr-description-file");
9
8
  /**
10
9
  * This plugin extracts package versions from R `DESCRIPTION` files.
11
10
  * It looks at the `Depends` and `Imports` fields to find package names and their version constraints.
@@ -24,12 +23,12 @@ class FlowrAnalyzerPackageVersionsDescriptionFilePlugin extends flowr_analyzer_p
24
23
  flowr_analyzer_description_file_plugin_1.descriptionFileLog.warn(`Found ${descFiles.length} description files, expected exactly one.`);
25
24
  }
26
25
  /** this will do the caching etc. for me */
27
- const deps = descFiles[0].content();
28
- this.retrieveVersionsFromField(ctx, deps, 'Depends', 'r');
29
- this.retrieveVersionsFromField(ctx, deps, 'Imports', 'package');
26
+ const deps = descFiles[0];
27
+ this.retrieveVersionsFromField(ctx, deps.depends() ?? []);
28
+ this.retrieveVersionsFromField(ctx, deps.imports() ?? []);
30
29
  }
31
- retrieveVersionsFromField(ctx, file, field, type) {
32
- for (const pkg of (0, flowr_description_file_1.parsePackagesWithVersions)(file.get(field) ?? [], type)) {
30
+ retrieveVersionsFromField(ctx, pkgs) {
31
+ for (const pkg of pkgs) {
33
32
  ctx.deps.addDependency(pkg);
34
33
  }
35
34
  }
@@ -36,12 +36,13 @@ async function executeDependenciesQuery({ analyzer, }, queries) {
36
36
  }
37
37
  const queryResults = functions.values().toArray().flat().length === 0 ? { kinds: {}, '.meta': { timing: 0 } } :
38
38
  await (0, query_1.executeQueriesOfSameType)(data, functions.entries().map(([c, f]) => makeCallContextQuery(f, c)).toArray().flat());
39
+ const g = (0, dependencies_query_format_1.getAllCategories)(queries);
39
40
  const results = Object.fromEntries(await Promise.all(functions.entries().map(async ([c, f]) => {
40
41
  const results = getResults(queries, { dataflow, config, normalize }, queryResults, c, f, data);
41
42
  // only default categories allow additional analyses, so we null-coalesce here!
42
43
  const enabled = query.enabledCategories;
43
44
  if (enabled === undefined || (enabled?.length > 0 && enabled.includes(c))) {
44
- await dependencies_query_format_1.DefaultDependencyCategories[c]?.additionalAnalysis?.(data, ignoreDefault, f, queryResults, results);
45
+ await g[c]?.additionalAnalysis?.(data, ignoreDefault, f, queryResults, results);
45
46
  }
46
47
  return [c, results];
47
48
  })));
@@ -5,7 +5,7 @@ import { executeDependenciesQuery } from './dependencies-query-executor';
5
5
  import type { FunctionInfo } from './function-info/function-info';
6
6
  import type { CallContextQueryResult } from '../call-context-query/call-context-query-format';
7
7
  import type { Range } from 'semver';
8
- import type { AsyncOrSync } from 'ts-essentials';
8
+ import type { AsyncOrSync, MarkOptional } from 'ts-essentials';
9
9
  import type { NamespaceInfo } from '../../../project/plugins/file-plugins/files/flowr-namespace-file';
10
10
  export declare const Unknown = "unknown";
11
11
  export interface DependencyCategorySettings {
@@ -13,6 +13,15 @@ export interface DependencyCategorySettings {
13
13
  functions: FunctionInfo[];
14
14
  /** this describes the global default value for this category, e.g., 'stdout' for write operations, please be aware, that this can be overwritten by a by-function default value */
15
15
  defaultValue?: string;
16
+ /**
17
+ * An optional additional analysis step that is executed after the main function-based analysis has been performed.
18
+ * To add or modify dependency info entries, simply modify the `result` array.
19
+ * @param data - The basic query data.
20
+ * @param ignoreDefault - Whether the default functions were ignored.
21
+ * @param functions - The functions used for this category.
22
+ * @param queryResults - The results of the call context query.
23
+ * @param result - The current result array to which additional dependency info can be added.
24
+ */
16
25
  additionalAnalysis?: (data: BasicQueryData, ignoreDefault: boolean, functions: FunctionInfo[], queryResults: CallContextQueryResult, result: DependencyInfo[]) => AsyncOrSync<void>;
17
26
  }
18
27
  export declare const DefaultDependencyCategories: {
@@ -52,7 +61,7 @@ export interface DependenciesQuery extends BaseQueryFormat, Partial<Record<`${De
52
61
  readonly type: 'dependencies';
53
62
  readonly enabledCategories?: DependencyCategoryName[];
54
63
  readonly ignoreDefaultFunctions?: boolean;
55
- readonly additionalCategories?: Record<string, Omit<DependencyCategorySettings, 'additionalAnalysis'>>;
64
+ readonly additionalCategories?: Record<string, MarkOptional<DependencyCategorySettings, 'additionalAnalysis'>>;
56
65
  }
57
66
  export type DependenciesQueryResult = BaseQueryResult & {
58
67
  [C in DefaultDependencyCategoryName]: DependencyInfo[];
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.11';
9
+ const version = '2.8.12';
10
10
  /**
11
11
  * Retrieves the current flowR version as a new {@link SemVer} object.
12
12
  */