@eagleoutice/flowr 2.7.5 → 2.8.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.
Files changed (208) hide show
  1. package/README.md +68 -65
  2. package/cli/wiki.js +1 -1
  3. package/control-flow/extract-cfg.js +3 -3
  4. package/control-flow/useless-loop.d.ts +1 -1
  5. package/control-flow/useless-loop.js +2 -2
  6. package/dataflow/cluster.js +3 -3
  7. package/dataflow/environments/built-in-config.d.ts +8 -4
  8. package/dataflow/environments/built-in.d.ts +27 -14
  9. package/dataflow/environments/built-in.js +27 -12
  10. package/dataflow/environments/default-builtin-config.d.ts +614 -3
  11. package/dataflow/environments/default-builtin-config.js +50 -15
  12. package/dataflow/environments/environment.js +3 -2
  13. package/dataflow/environments/identifier.d.ts +5 -1
  14. package/dataflow/environments/reference-to-maybe.d.ts +2 -2
  15. package/dataflow/environments/reference-to-maybe.js +23 -14
  16. package/dataflow/environments/resolve-by-name.d.ts +6 -2
  17. package/dataflow/environments/resolve-by-name.js +5 -1
  18. package/dataflow/environments/scoping.js +1 -3
  19. package/dataflow/eval/resolve/alias-tracking.js +5 -1
  20. package/dataflow/extractor.js +3 -3
  21. package/dataflow/fn/exceptions-of-function.d.ts +13 -0
  22. package/dataflow/fn/exceptions-of-function.js +47 -0
  23. package/dataflow/fn/higher-order-function.d.ts +1 -1
  24. package/dataflow/fn/higher-order-function.js +3 -3
  25. package/dataflow/fn/recursive-function.d.ts +6 -0
  26. package/dataflow/fn/recursive-function.js +32 -0
  27. package/dataflow/graph/call-graph.d.ts +10 -0
  28. package/dataflow/graph/call-graph.js +209 -0
  29. package/dataflow/graph/dataflowgraph-builder.d.ts +7 -2
  30. package/dataflow/graph/dataflowgraph-builder.js +14 -9
  31. package/dataflow/graph/diff-dataflow-graph.js +96 -2
  32. package/dataflow/graph/graph.d.ts +10 -7
  33. package/dataflow/graph/graph.js +7 -8
  34. package/dataflow/graph/vertex.d.ts +6 -3
  35. package/dataflow/hooks.d.ts +30 -0
  36. package/dataflow/hooks.js +38 -0
  37. package/dataflow/info.d.ts +28 -5
  38. package/dataflow/info.js +66 -31
  39. package/dataflow/internal/linker.d.ts +13 -3
  40. package/dataflow/internal/linker.js +155 -53
  41. package/dataflow/internal/process/functions/call/argument/unpack-argument.d.ts +4 -0
  42. package/dataflow/internal/process/functions/call/argument/unpack-argument.js +7 -0
  43. package/dataflow/internal/process/functions/call/built-in/built-in-apply.d.ts +1 -1
  44. package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +19 -3
  45. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +14 -0
  46. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +30 -0
  47. package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +2 -1
  48. package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +24 -17
  49. package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +2 -1
  50. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +5 -1
  51. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +59 -21
  52. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +4 -3
  53. package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.d.ts +34 -0
  54. package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.js +92 -0
  55. package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +1 -0
  56. package/dataflow/internal/process/functions/call/built-in/built-in-stop-if-not.d.ts +21 -0
  57. package/dataflow/internal/process/functions/call/built-in/built-in-stop-if-not.js +129 -0
  58. package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.d.ts +16 -0
  59. package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.js +127 -0
  60. package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +5 -3
  61. package/dataflow/internal/process/functions/call/common.d.ts +13 -1
  62. package/dataflow/internal/process/functions/call/common.js +33 -2
  63. package/dataflow/internal/process/functions/call/known-call-handling.d.ts +13 -1
  64. package/dataflow/internal/process/functions/call/known-call-handling.js +29 -3
  65. package/dataflow/internal/process/functions/call/named-call-handling.js +2 -1
  66. package/dataflow/internal/process/functions/call/unnamed-call-handling.js +6 -4
  67. package/dataflow/internal/process/functions/process-argument.js +7 -6
  68. package/dataflow/internal/process/functions/process-parameter.js +2 -1
  69. package/dataflow/internal/process/process-named-call.d.ts +2 -2
  70. package/dataflow/internal/process/process-symbol.js +3 -2
  71. package/dataflow/internal/process/process-value.d.ts +3 -2
  72. package/dataflow/internal/process/process-value.js +8 -6
  73. package/dataflow/origin/dfg-get-origin.js +2 -1
  74. package/dataflow/origin/dfg-get-symbol-refs.js +1 -1
  75. package/documentation/doc-readme.d.ts +1 -1
  76. package/documentation/doc-readme.js +6 -6
  77. package/documentation/doc-util/doc-code.js +1 -1
  78. package/documentation/doc-util/doc-dfg.d.ts +1 -0
  79. package/documentation/doc-util/doc-dfg.js +7 -4
  80. package/documentation/doc-util/doc-query.d.ts +1 -0
  81. package/documentation/doc-util/doc-query.js +1 -1
  82. package/documentation/doc-util/doc-repl.d.ts +2 -1
  83. package/documentation/doc-util/doc-repl.js +11 -3
  84. package/documentation/wiki-analyzer.js +2 -0
  85. package/documentation/wiki-dataflow-graph.js +59 -16
  86. package/documentation/wiki-interface.js +33 -5
  87. package/documentation/wiki-mk/doc-context.d.ts +2 -1
  88. package/documentation/wiki-mk/doc-context.js +2 -2
  89. package/documentation/wiki-mk/doc-maker.js +4 -3
  90. package/documentation/wiki-normalized-ast.js +6 -0
  91. package/documentation/wiki-query.js +109 -1
  92. package/linter/linter-rules.d.ts +1 -1
  93. package/linter/rules/seeded-randomness.js +17 -12
  94. package/linter/rules/useless-loop.d.ts +1 -1
  95. package/package.json +9 -11
  96. package/project/cache/flowr-analyzer-cache.d.ts +11 -0
  97. package/project/cache/flowr-analyzer-cache.js +19 -0
  98. package/project/context/flowr-analyzer-dependencies-context.d.ts +6 -1
  99. package/project/context/flowr-analyzer-dependencies-context.js +6 -0
  100. package/project/context/flowr-analyzer-files-context.d.ts +5 -2
  101. package/project/context/flowr-analyzer-files-context.js +24 -17
  102. package/project/context/flowr-file.d.ts +9 -4
  103. package/project/context/flowr-file.js +20 -6
  104. package/project/flowr-analyzer.d.ts +11 -0
  105. package/project/flowr-analyzer.js +6 -0
  106. package/project/plugins/file-plugins/files/flowr-description-file.d.ts +11 -3
  107. package/project/plugins/file-plugins/files/flowr-description-file.js +38 -28
  108. package/project/plugins/file-plugins/files/flowr-jupyter-file.js +1 -1
  109. package/project/plugins/file-plugins/files/flowr-namespace-file.js +1 -1
  110. package/project/plugins/file-plugins/files/flowr-news-file.js +1 -1
  111. package/project/plugins/file-plugins/files/flowr-rmarkdown-file.js +1 -1
  112. package/project/plugins/file-plugins/flowr-analyzer-description-file-plugin.js +1 -1
  113. package/project/plugins/file-plugins/flowr-analyzer-file-plugin.d.ts +4 -1
  114. package/project/plugins/file-plugins/flowr-analyzer-file-plugin.js +3 -0
  115. package/project/plugins/file-plugins/{flowr-analyzer-namespace-file-plugin.d.ts → flowr-analyzer-namespace-files-plugin.d.ts} +1 -1
  116. package/project/plugins/file-plugins/{flowr-analyzer-namespace-file-plugin.js → flowr-analyzer-namespace-files-plugin.js} +4 -4
  117. package/project/plugins/file-plugins/flowr-analyzer-test-file-plugin.d.ts +26 -0
  118. package/project/plugins/file-plugins/flowr-analyzer-test-file-plugin.js +39 -0
  119. package/project/plugins/file-plugins/flowr-analyzer-vignette-file-plugin.d.ts +26 -0
  120. package/project/plugins/file-plugins/flowr-analyzer-vignette-file-plugin.js +39 -0
  121. package/project/plugins/flowr-analyzer-plugin-defaults.js +6 -2
  122. package/project/plugins/package-version-plugins/flowr-analyzer-package-versions-description-file-plugin.js +3 -13
  123. package/project/plugins/package-version-plugins/package.d.ts +1 -1
  124. package/project/plugins/package-version-plugins/package.js +3 -3
  125. package/project/plugins/plugin-registry.d.ts +4 -2
  126. package/project/plugins/plugin-registry.js +6 -2
  127. package/project/plugins/project-discovery/flowr-analyzer-project-discovery-plugin.d.ts +11 -0
  128. package/project/plugins/project-discovery/flowr-analyzer-project-discovery-plugin.js +5 -2
  129. package/queries/catalog/call-context-query/call-context-query-format.d.ts +4 -12
  130. package/queries/catalog/call-graph-query/call-graph-query-executor.d.ts +6 -0
  131. package/queries/catalog/call-graph-query/call-graph-query-executor.js +21 -0
  132. package/queries/catalog/call-graph-query/call-graph-query-format.d.ts +21 -0
  133. package/queries/catalog/call-graph-query/call-graph-query-format.js +32 -0
  134. package/queries/catalog/dataflow-query/dataflow-query-executor.js +4 -3
  135. package/queries/catalog/dependencies-query/dependencies-query-executor.js +29 -3
  136. package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +1 -0
  137. package/queries/catalog/dependencies-query/function-info/function-info.d.ts +8 -1
  138. package/queries/catalog/dependencies-query/function-info/write-functions.js +13 -0
  139. package/queries/catalog/does-call-query/does-call-query-executor.d.ts +6 -0
  140. package/queries/catalog/does-call-query/does-call-query-executor.js +100 -0
  141. package/queries/catalog/does-call-query/does-call-query-format.d.ts +51 -0
  142. package/queries/catalog/does-call-query/does-call-query-format.js +102 -0
  143. package/queries/catalog/files-query/files-query-executor.js +4 -4
  144. package/queries/catalog/files-query/files-query-format.d.ts +2 -1
  145. package/queries/catalog/files-query/files-query-format.js +18 -2
  146. package/queries/catalog/id-map-query/id-map-query-executor.js +4 -3
  147. package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.d.ts +18 -0
  148. package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.js +56 -0
  149. package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.d.ts +34 -0
  150. package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.js +54 -0
  151. package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor.js +3 -28
  152. package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.d.ts +6 -0
  153. package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.js +12 -0
  154. package/queries/catalog/inspect-recursion-query/inspect-recursion-query-executor.d.ts +6 -0
  155. package/queries/catalog/inspect-recursion-query/inspect-recursion-query-executor.js +23 -0
  156. package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.d.ts +28 -0
  157. package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.js +44 -0
  158. package/queries/catalog/linter-query/linter-query-format.js +4 -1
  159. package/queries/catalog/location-map-query/location-map-query-executor.js +1 -1
  160. package/queries/catalog/normalized-ast-query/normalized-ast-query-executor.js +4 -3
  161. package/queries/catalog/project-query/project-query-executor.js +9 -3
  162. package/queries/catalog/project-query/project-query-format.d.ts +8 -3
  163. package/queries/catalog/project-query/project-query-format.js +35 -9
  164. package/queries/query.d.ts +34 -2
  165. package/queries/query.js +9 -0
  166. package/r-bridge/data/data.d.ts +10 -5
  167. package/r-bridge/data/data.js +11 -5
  168. package/r-bridge/lang-4.x/ast/model/model.d.ts +7 -7
  169. package/r-bridge/lang-4.x/ast/model/nodes/r-access.d.ts +2 -2
  170. package/r-bridge/lang-4.x/ast/model/nodes/r-argument.d.ts +2 -2
  171. package/r-bridge/lang-4.x/ast/model/nodes/r-binary-op.d.ts +2 -2
  172. package/r-bridge/lang-4.x/ast/model/nodes/r-comment.d.ts +5 -2
  173. package/r-bridge/lang-4.x/ast/model/nodes/r-comment.js +8 -0
  174. package/r-bridge/lang-4.x/ast/model/nodes/r-expression-list.d.ts +2 -2
  175. package/r-bridge/lang-4.x/ast/model/nodes/r-for-loop.d.ts +2 -2
  176. package/r-bridge/lang-4.x/ast/model/nodes/r-function-call.d.ts +3 -3
  177. package/r-bridge/lang-4.x/ast/model/nodes/r-function-definition.d.ts +2 -2
  178. package/r-bridge/lang-4.x/ast/model/nodes/r-if-then-else.d.ts +2 -2
  179. package/r-bridge/lang-4.x/ast/model/nodes/r-parameter.d.ts +2 -2
  180. package/r-bridge/lang-4.x/ast/model/nodes/r-pipe.d.ts +2 -2
  181. package/r-bridge/lang-4.x/ast/model/nodes/r-repeat-loop.d.ts +2 -2
  182. package/r-bridge/lang-4.x/ast/model/nodes/r-unary-op.d.ts +2 -2
  183. package/r-bridge/lang-4.x/ast/model/nodes/r-while-loop.d.ts +2 -2
  184. package/r-bridge/lang-4.x/ast/parser/main/internal/other/normalize-comment.js +0 -1
  185. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +0 -2
  186. package/r-bridge/roxygen2/roxygen-ast.d.ts +218 -0
  187. package/r-bridge/roxygen2/roxygen-ast.js +82 -0
  188. package/r-bridge/roxygen2/roxygen-parse.d.ts +24 -0
  189. package/r-bridge/roxygen2/roxygen-parse.js +214 -0
  190. package/reconstruct/auto-select/magic-comments.js +4 -4
  191. package/slicing/static/slice-call.js +3 -4
  192. package/slicing/static/static-slicer.js +2 -2
  193. package/statistics/features/supported/defined-functions/defined-functions.js +1 -1
  194. package/util/collections/defaultmap.d.ts +3 -3
  195. package/util/mermaid/dfg.js +5 -5
  196. package/util/objects.js +1 -1
  197. package/util/r-author.d.ts +5 -0
  198. package/util/r-author.js +110 -0
  199. package/util/r-license.d.ts +32 -0
  200. package/util/r-license.js +217 -0
  201. package/util/r-version.d.ts +19 -0
  202. package/util/r-version.js +106 -0
  203. package/util/range.d.ts +6 -0
  204. package/util/range.js +7 -0
  205. package/util/simple-df/dfg-ascii.js +2 -2
  206. package/util/text/args.d.ts +9 -0
  207. package/util/text/args.js +65 -0
  208. package/util/version.js +1 -1
@@ -33,7 +33,7 @@ function formatRange(range) {
33
33
  }
34
34
  return `${range[0]}.${range[1]}-${range[2]}.${range[3]}`;
35
35
  }
36
- function subflowToMermaid(nodeId, exitPoints, subflow, mermaid, idPrefix = '') {
36
+ function subflowToMermaid(nodeId, subflow, mermaid, idPrefix = '') {
37
37
  if (subflow === undefined) {
38
38
  return;
39
39
  }
@@ -166,7 +166,7 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark, includeOnlyIds) {
166
166
  }
167
167
  else {
168
168
  const escapedName = (0, mermaid_1.escapeMarkdown)(node ? `[${node.type}] ${lexeme}` : '??');
169
- const deps = info.cds ? ', :may:' + info.cds.map(c => c.id + (c.when ? '+' : '-')).join(',') : '';
169
+ const deps = info.controlDependencies ? ', :may:' + info.controlDependencies.map(c => c.id + (c.when ? '+' : '-')).join(',') : '';
170
170
  const lnks = info.link?.origin ? ', :links:' + info.link.origin.join(',') : '';
171
171
  const n = node?.info.fullRange ?? node?.location ?? (node?.type === type_1.RType.ExpressionList ? node?.grouping?.[0].location : undefined);
172
172
  mermaid.nodeLines.push(` ${idPrefix}${id}${open}"\`${escapedName}${escapedName.length > 10 ? '\n ' : ' '}(${id}${deps}${lnks})\n *${formatRange(n)}*${fCall ? displayFunctionArgMapping(info.args) : ''}\`"${close}`);
@@ -182,7 +182,7 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark, includeOnlyIds) {
182
182
  mermaid.nodeLines.push(' %% No edges found for ' + id);
183
183
  return;
184
184
  }
185
- const artificialCdEdges = (info.cds ?? []).map(x => [x.id, { types: new Set([x.when ? 'CD-True' : 'CD-False']) }]);
185
+ const artificialCdEdges = (info.controlDependencies ?? []).map(x => [x.id, { types: new Set([x.when ? 'CD-True' : 'CD-False']) }]);
186
186
  // eslint-disable-next-line prefer-const
187
187
  for (let [target, edge] of [...edges[1], ...artificialCdEdges]) {
188
188
  if (includeOnlyIds && !includeOnlyIds.has(target)) {
@@ -207,14 +207,14 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark, includeOnlyIds) {
207
207
  mermaid.edgeLines.push(` linkStyle ${mermaid.presentEdges.size - 1} stroke:gray;`);
208
208
  if (!mermaid.presentVertices.has(target)) {
209
209
  mermaid.nodeLines.push(` ${idPrefix}${target}["\`Built-In:\n${(0, mermaid_1.escapeMarkdown)(String(originalTarget).replace('built-in:', ''))}\`"]`);
210
- mermaid.nodeLines.push(` style ${idPrefix}${target} stroke:gray,fill:lightgray,stroke-width:2px,opacity:.8;`);
210
+ mermaid.nodeLines.push(` style ${idPrefix}${target} stroke:gray,fill:gray,stroke-width:2px,opacity:.8;`);
211
211
  mermaid.presentVertices.add(target);
212
212
  }
213
213
  }
214
214
  }
215
215
  }
216
216
  if (info.tag === vertex_1.VertexType.FunctionDefinition) {
217
- subflowToMermaid(id, info.exitPoints, info.subflow, mermaid, idPrefix);
217
+ subflowToMermaid(id, info.subflow, mermaid, idPrefix);
218
218
  }
219
219
  }
220
220
  // make the passing of root ids more performant again
package/util/objects.js CHANGED
@@ -30,7 +30,7 @@ function deepMergeObject(base, addon) {
30
30
  deepMergeObjectWithResult(addon, base, result);
31
31
  }
32
32
  else if (baseIsArray && addonIsArray) {
33
- return [...base, ...addon];
33
+ return base.concat(addon);
34
34
  }
35
35
  else {
36
36
  throw new Error('cannot merge object with array!');
@@ -37,3 +37,8 @@ export declare function rAuthorInfoToReadable(author: RAuthorInfo): string;
37
37
  * For now, this works *without* the full dataflow engine, so complex cases may not be parsed correctly.
38
38
  */
39
39
  export declare function parseRAuthorString(authorString: string): RAuthorInfo[];
40
+ /**
41
+ * In contrast to `parseRAuthorString`, this function parses simple textual author strings,
42
+ * like `First Middle Last <email> [roles] (comment)...`. It does not support the full R `person()` syntax.
43
+ */
44
+ export declare function parseTextualAuthorString(authorString: string, addRoles?: AuthorRole[]): RAuthorInfo[];
package/util/r-author.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AuthorRole = void 0;
4
4
  exports.rAuthorInfoToReadable = rAuthorInfoToReadable;
5
5
  exports.parseRAuthorString = parseRAuthorString;
6
+ exports.parseTextualAuthorString = parseTextualAuthorString;
6
7
  const args_1 = require("./text/args");
7
8
  const assert_1 = require("./assert");
8
9
  const objects_1 = require("./objects");
@@ -191,4 +192,113 @@ function parseRPersonCall(personCall) {
191
192
  orcid: comments?.orcid
192
193
  });
193
194
  }
195
+ function collectUntil(source, anyOf) {
196
+ let collected = '';
197
+ let i = 0;
198
+ while (i < source.length && !anyOf.test(source[i])) {
199
+ collected += source[i];
200
+ i++;
201
+ }
202
+ return { collected, rest: source.slice(i) };
203
+ }
204
+ /**
205
+ * In contrast to `parseRAuthorString`, this function parses simple textual author strings,
206
+ * like `First Middle Last <email> [roles] (comment)...`. It does not support the full R `person()` syntax.
207
+ */
208
+ function parseTextualAuthorString(authorString, addRoles = []) {
209
+ const parts = (0, args_1.splitOnNestingSensitive)(authorString, 'and', {
210
+ '<': '>',
211
+ '[': ']',
212
+ '(': ')',
213
+ '"': '"',
214
+ "'": "'"
215
+ });
216
+ const authors = [];
217
+ for (const part of parts) {
218
+ const name = collectUntil(part.trim(), /[<[(]/);
219
+ const others = parseOnRest(name.rest);
220
+ const c = processComment(others.comment);
221
+ authors.push((0, objects_1.compactRecord)({
222
+ name: name.collected.trim().split(/\s+/),
223
+ email: others.email,
224
+ roles: others.roles.concat(addRoles),
225
+ comment: c.comment,
226
+ orcid: c.orcid
227
+ }));
228
+ }
229
+ return authors;
230
+ }
231
+ function processComment(comment) {
232
+ if (!comment) {
233
+ return {};
234
+ }
235
+ const parts = comment.split(/\s*[,;]\s*/);
236
+ const comments = [];
237
+ let orcid = undefined;
238
+ for (const part of parts) {
239
+ const orcidExtract = /ORCID\s*[:= ]\s*(?<orcid>.+)/i;
240
+ const match = part.match(orcidExtract);
241
+ if (match && match.groups && match.groups['orcid']) {
242
+ orcid = match.groups['orcid'].trim();
243
+ }
244
+ else {
245
+ comments.push(part.trim());
246
+ }
247
+ }
248
+ if (orcid) {
249
+ return { comment: comments.length > 0 ? comments : undefined, orcid };
250
+ }
251
+ else {
252
+ return { comment: [comment] };
253
+ }
254
+ }
255
+ function parseOnRest(rest) {
256
+ let email = undefined;
257
+ let roles = [];
258
+ let comment = undefined;
259
+ while (rest.length > 0) {
260
+ rest = rest.trim();
261
+ switch (rest[0]) {
262
+ case '<': {
263
+ const emailEnd = rest.indexOf('>');
264
+ if (emailEnd !== -1) {
265
+ email = rest.slice(1, emailEnd).trim();
266
+ rest = rest.slice(emailEnd + 1);
267
+ }
268
+ else {
269
+ rest = '';
270
+ }
271
+ break;
272
+ }
273
+ case '[': {
274
+ const rolesEnd = rest.indexOf(']');
275
+ if (rolesEnd !== -1) {
276
+ const rolesStr = rest.slice(1, rolesEnd).trim();
277
+ roles = rolesStr.split(/\s*,\s*/).map(r => r);
278
+ rest = rest.slice(rolesEnd + 1);
279
+ }
280
+ else {
281
+ rest = '';
282
+ }
283
+ break;
284
+ }
285
+ case '(': {
286
+ const commentEnd = rest.indexOf(')');
287
+ if (commentEnd !== -1) {
288
+ comment = rest.slice(1, commentEnd).trim();
289
+ rest = rest.slice(commentEnd + 1);
290
+ }
291
+ else {
292
+ rest = '';
293
+ }
294
+ break;
295
+ }
296
+ default: {
297
+ rest = '';
298
+ break;
299
+ }
300
+ }
301
+ }
302
+ return { email, roles, comment };
303
+ }
194
304
  //# sourceMappingURL=r-author.js.map
@@ -0,0 +1,32 @@
1
+ import type { Range } from 'semver';
2
+ export interface RLicenseInfo {
3
+ type: 'license';
4
+ license: string;
5
+ versionConstraint?: Range;
6
+ }
7
+ export interface RLicenseExceptionInfo {
8
+ type: 'exception';
9
+ exception: string;
10
+ }
11
+ export interface RLicenseCombinationInfo {
12
+ type: 'combination';
13
+ combination: 'and' | 'or' | 'with';
14
+ elements: [left: RLicenseElementInfo, right: RLicenseElementInfo];
15
+ }
16
+ export interface NoLicenseInfo {
17
+ type: 'no-license';
18
+ }
19
+ /**
20
+ * The structured representation of an R license element.
21
+ * This can be a license, an exception, a combination of licenses, or no license.
22
+ * @see {@link parseRLicense} and {@link stringifyRLicense} to parse and stringify R license strings.
23
+ */
24
+ export type RLicenseElementInfo = RLicenseInfo | RLicenseExceptionInfo | RLicenseCombinationInfo | NoLicenseInfo;
25
+ /**
26
+ * Parses an R license string into its structured representation.
27
+ */
28
+ export declare function parseRLicense(licenseString: string): RLicenseElementInfo;
29
+ /**
30
+ * Stringifies an R license element back into its string representation.
31
+ */
32
+ export declare function stringifyRLicense(license: RLicenseElementInfo): string;
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseRLicense = parseRLicense;
4
+ exports.stringifyRLicense = stringifyRLicense;
5
+ const assert_1 = require("./assert");
6
+ const objects_1 = require("./objects");
7
+ const r_version_1 = require("./r-version");
8
+ /**
9
+ * Parses an R license string into its structured representation.
10
+ */
11
+ function parseRLicense(licenseString) {
12
+ return parseLicenseInfo(skipWhitespace({ position: 0, remInput: licenseString })).element;
13
+ }
14
+ /**
15
+ * Stringifies an R license element back into its string representation.
16
+ */
17
+ function stringifyRLicense(license) {
18
+ const t = license.type;
19
+ switch (t) {
20
+ case 'no-license':
21
+ return 'NO LICENSE';
22
+ case 'license':
23
+ return license.versionConstraint ? `${license.license} (${license.versionConstraint.raw})` : license.license;
24
+ case 'exception':
25
+ return `with ${license.exception}`;
26
+ case 'combination': {
27
+ const left = stringifyRLicense(license.elements[0]);
28
+ const right = stringifyRLicense(license.elements[1]);
29
+ const leftStr = license.elements[0].type === 'combination' ? `(${left})` : left;
30
+ const rightStr = license.elements[1].type === 'combination' ? `(${right})` : right;
31
+ return `${leftStr} ${license.combination} ${rightStr}`;
32
+ }
33
+ default:
34
+ (0, assert_1.assertUnreachable)(t);
35
+ }
36
+ }
37
+ function parseLicenseInfo(info) {
38
+ info = skipWhitespace(info);
39
+ if (info.remInput.length === 0) {
40
+ return { ...info, element: { type: 'no-license' } };
41
+ }
42
+ else if (info.remInput.startsWith('(')) {
43
+ return parseParenthesizedExpression(info);
44
+ }
45
+ else {
46
+ return parseBinaryOperator(info);
47
+ }
48
+ }
49
+ function parseParenthesizedExpression(info) {
50
+ const openParen = consumeString(info, '(');
51
+ (0, assert_1.guard)(openParen.element, `Expected (, but found ${info.remInput[0]} at position ${info.position}`);
52
+ const innerInfo = parseLicenseInfo(openParen);
53
+ const closeParen = consumeString(innerInfo, ')');
54
+ (0, assert_1.guard)(closeParen.element, `Expected ), but found ${innerInfo.remInput[0]} at position ${innerInfo.position}`);
55
+ return { ...closeParen, element: innerInfo.element };
56
+ }
57
+ function skipWhitespace({ remInput, position }) {
58
+ let idx = remInput.search(/\S/);
59
+ if (idx === -1) {
60
+ idx = remInput.length;
61
+ }
62
+ position += idx;
63
+ remInput = remInput.slice(idx);
64
+ return { position, remInput };
65
+ }
66
+ function consumeLicenseName(info) {
67
+ info = skipWhitespace(info);
68
+ let licenseName = '';
69
+ let isAtWhitespace = false;
70
+ for (let i = 0; i < info.remInput.length; i++) {
71
+ const char = info.remInput[i];
72
+ if (/[()<>~!=,&|+]/.test(char)) {
73
+ break;
74
+ }
75
+ else {
76
+ isAtWhitespace = /\s/.test(char);
77
+ }
78
+ if (isAtWhitespace) {
79
+ if (/^\s*(with|and|or)\s+/i.test(info.remInput.slice(i))) {
80
+ break;
81
+ }
82
+ }
83
+ licenseName += char;
84
+ }
85
+ const newInfo = {
86
+ position: info.position + licenseName.length,
87
+ remInput: info.remInput.slice(licenseName.length)
88
+ };
89
+ // file licenses are a special case!
90
+ if (licenseName && /^file[\s-]+license$/i.test(licenseName.trim())) {
91
+ return { ...newInfo, element: 'file LICENSE' };
92
+ }
93
+ return { ...newInfo, element: licenseName?.trim() ?? '' };
94
+ }
95
+ function makeRange(rangeStr) {
96
+ try {
97
+ return (0, r_version_1.parseRRange)(rangeStr);
98
+ }
99
+ catch {
100
+ return undefined;
101
+ }
102
+ }
103
+ function parseLicenseElement(info) {
104
+ const licenseName = consumeLicenseName(info);
105
+ info = skipWhitespace(licenseName);
106
+ // may be followed by version constraint in parentheses or directly
107
+ let versionConstraint;
108
+ if (/^\(\s*?[\d<>=!~]/.test(info.remInput)) {
109
+ // version constraint
110
+ if (info.remInput.startsWith('(')) {
111
+ const openParen = consumeString(info, '(');
112
+ (0, assert_1.guard)(openParen.element, `Expected (, but found ${info.remInput[0]} at position ${info.position}`);
113
+ info = skipWhitespace(openParen);
114
+ // consume until closing parenthesis
115
+ const versionStr = consumeUntilString(info, ')');
116
+ versionConstraint = makeRange(versionStr.element);
117
+ const closeParen = consumeString(versionStr, ')');
118
+ (0, assert_1.guard)(closeParen.element, `Expected ), but found ${versionStr.remInput[0]} at position ${versionStr.position}`);
119
+ info = skipWhitespace(closeParen);
120
+ }
121
+ else {
122
+ // consume until whitespace or special character
123
+ const versionStr = consumeRegexp(info, /^[\d<>=!~.\s]+/);
124
+ versionConstraint = versionStr.element ? makeRange(versionStr.element) : undefined;
125
+ info = skipWhitespace(versionStr);
126
+ }
127
+ }
128
+ const licenseInfo = (0, objects_1.compactRecord)({
129
+ type: 'license',
130
+ license: licenseName.element,
131
+ versionConstraint
132
+ });
133
+ return { ...info, element: licenseInfo };
134
+ }
135
+ const operators = {
136
+ 'and': ['and', '+', '&'],
137
+ 'or': ['or', '|'],
138
+ 'with': ['with']
139
+ };
140
+ function parseBinaryOperator(info) {
141
+ const license = parseLicenseElement(info);
142
+ info = skipWhitespace(license);
143
+ const operator = tryConsumeOperator(info);
144
+ if (operator.element) {
145
+ info = skipWhitespace(operator);
146
+ let rightLicense = parseLicenseInfo(info);
147
+ if (operator.element === 'with' && rightLicense.element.type === 'license') {
148
+ rightLicense = {
149
+ ...rightLicense,
150
+ element: {
151
+ type: 'exception',
152
+ exception: rightLicense.element.license
153
+ }
154
+ };
155
+ }
156
+ const combination = {
157
+ type: 'combination',
158
+ combination: operator.element,
159
+ elements: [license.element, rightLicense.element]
160
+ };
161
+ return { ...rightLicense, element: combination };
162
+ }
163
+ return { ...info, element: license.element };
164
+ }
165
+ function tryConsumeOperator(info) {
166
+ for (const [opName, opSymbols] of Object.entries(operators)) {
167
+ for (const symbol of opSymbols) {
168
+ if (info.remInput.toLowerCase().startsWith(symbol)) {
169
+ const newInfo = {
170
+ position: info.position + symbol.length,
171
+ remInput: info.remInput.slice(symbol.length)
172
+ };
173
+ return { ...newInfo, element: opName };
174
+ }
175
+ }
176
+ }
177
+ return { ...info, element: undefined };
178
+ }
179
+ function consumeString(info, str) {
180
+ info = skipWhitespace(info);
181
+ if (info.remInput.startsWith(str)) {
182
+ const newInfo = {
183
+ position: info.position + str.length,
184
+ remInput: info.remInput.slice(str.length)
185
+ };
186
+ return { ...newInfo, element: true };
187
+ }
188
+ else {
189
+ return { ...info, element: false };
190
+ }
191
+ }
192
+ function consumeUntilString(info, str) {
193
+ let idx = info.remInput.indexOf(str);
194
+ if (idx === -1) {
195
+ idx = info.remInput.length;
196
+ }
197
+ const consumed = info.remInput.slice(0, idx);
198
+ const newInfo = {
199
+ position: info.position + idx,
200
+ remInput: info.remInput.slice(idx)
201
+ };
202
+ return { ...newInfo, element: consumed };
203
+ }
204
+ function consumeRegexp(info, regex) {
205
+ info = skipWhitespace(info);
206
+ const match = info.remInput.match(regex);
207
+ if (match && match.index === 0) {
208
+ const matchedStr = match[0];
209
+ const newInfo = {
210
+ position: info.position + matchedStr.length,
211
+ remInput: info.remInput.slice(matchedStr.length)
212
+ };
213
+ return { ...newInfo, element: matchedStr };
214
+ }
215
+ return { ...info, element: null };
216
+ }
217
+ //# sourceMappingURL=r-license.js.map
@@ -0,0 +1,19 @@
1
+ import { Range, SemVer } from 'semver';
2
+ /**
3
+ * This parses an R version string and returns a SemVer object.
4
+ * In contrast to just using `new SemVer(version)`, this function also tries to
5
+ * normalize R's much free-er versioning scheme into valid SemVer versions.
6
+ * You can always access the original version string via the `str` property on the returned object.
7
+ */
8
+ export declare function parseRVersion(version: string): SemVer & {
9
+ str: string;
10
+ };
11
+ /**
12
+ * This parses an R version range string and returns a SemVer Range object.
13
+ * In contrast to just using `new Range(range)`, this function also tries to
14
+ * normalize R's much free-er versioning scheme into valid SemVer ranges.
15
+ * You can always access the original range string via the `str` property on the returned object.
16
+ */
17
+ export declare function parseRRange(range: string): Range & {
18
+ str: string;
19
+ };
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseRVersion = parseRVersion;
4
+ exports.parseRRange = parseRRange;
5
+ const semver_1 = require("semver");
6
+ const assert_1 = require("./assert");
7
+ function makeVersion(version, original) {
8
+ const semver = new semver_1.SemVer(version);
9
+ semver.str = original;
10
+ return semver;
11
+ }
12
+ /**
13
+ * Additionally, this transforms `a-b.c` into `a.0.0-b.c` and `a.b-c.d` into `a.b.0-c.d` to
14
+ * ensure valid SemVer format.
15
+ */
16
+ function normalizeTooShortVersions(versions) {
17
+ const TooShortVersionRegex = /(^|(?<=[^\d.-]))(?<major>\d+)(\.(?<minor>\d+))?\.?-(?<prerelease>[0-9A-Za-z-.]+)(\s|$)/g;
18
+ let newVersions = '';
19
+ let match;
20
+ while ((match = TooShortVersionRegex.exec(versions)) !== null) {
21
+ const { major, minor, prerelease } = match.groups;
22
+ const prefix = versions.slice(0, match.index);
23
+ let newVersion = '';
24
+ if (minor === undefined) {
25
+ // only major version present
26
+ newVersion = `${major}.0.0-${prerelease}`;
27
+ }
28
+ else {
29
+ // major and minor version present, but dot before prerelease
30
+ newVersion = `${major}.${minor}.0-${prerelease}`;
31
+ }
32
+ newVersions += `${prefix}${newVersion}`;
33
+ versions = versions.slice(match.index + match[0].length);
34
+ }
35
+ newVersions += versions; // append any remaining part
36
+ return newVersions;
37
+ }
38
+ /**
39
+ * For every version `a.b.c.d.e...` converts it to `a.b.c-d.e...`
40
+ * If the version already contains a prerelease part, it is appended:
41
+ * `a.b.c.d.e-prerelease...` becomes `a.b.c-d.e-prerelease...`
42
+ */
43
+ function normalizeAdditionalVersionsToPrerelease(version) {
44
+ version = normalizeTooShortVersions(version);
45
+ const AdditionalVersionRegex = /(\d+\.\d+\.\d+)(?<additional>(\.\d+)+)(-(?<prerelease>[0-9A-Za-z-.]+))?/g;
46
+ let match;
47
+ let newVersion = '';
48
+ // repeat until no more matches
49
+ while ((match = AdditionalVersionRegex.exec(version)) !== null) {
50
+ // append to new version, first take over anything before the match
51
+ const prefix = version.slice(0, match.index);
52
+ const { additional, prerelease } = match.groups;
53
+ const additionalParts = additional.slice(1).split('.'); // remove leading dot and split
54
+ if (additionalParts.length === 0) {
55
+ continue; // nothing to do
56
+ }
57
+ let newPrerelease = additionalParts.join('.');
58
+ if (prerelease) {
59
+ newPrerelease = `${newPrerelease}-${prerelease}`;
60
+ }
61
+ newVersion = `${prefix}${match[1]}-${newPrerelease}`;
62
+ version = version.slice(match.index + match[0].length);
63
+ }
64
+ newVersion += version; // append any remaining part
65
+ return newVersion;
66
+ }
67
+ /**
68
+ * This parses an R version string and returns a SemVer object.
69
+ * In contrast to just using `new SemVer(version)`, this function also tries to
70
+ * normalize R's much free-er versioning scheme into valid SemVer versions.
71
+ * You can always access the original version string via the `str` property on the returned object.
72
+ */
73
+ function parseRVersion(version) {
74
+ try {
75
+ return makeVersion(version, version);
76
+ }
77
+ catch { /* do nothing */ }
78
+ try {
79
+ const normalized = normalizeAdditionalVersionsToPrerelease(version);
80
+ return makeVersion(normalized, version);
81
+ }
82
+ catch { /* do nothing */ }
83
+ const coerced = (0, semver_1.coerce)(version, { loose: true, includePrerelease: true });
84
+ (0, assert_1.guard)(coerced !== null, `Could not coerce R version "${version}" to SemVer`);
85
+ return makeVersion(coerced.version, version);
86
+ }
87
+ function makeRange(range, original) {
88
+ const semverRange = new semver_1.Range(range);
89
+ semverRange.str = original;
90
+ return semverRange;
91
+ }
92
+ /**
93
+ * This parses an R version range string and returns a SemVer Range object.
94
+ * In contrast to just using `new Range(range)`, this function also tries to
95
+ * normalize R's much free-er versioning scheme into valid SemVer ranges.
96
+ * You can always access the original range string via the `str` property on the returned object.
97
+ */
98
+ function parseRRange(range) {
99
+ try {
100
+ return makeRange(range, range);
101
+ }
102
+ catch { /* try to normalize R range to SemVer */ }
103
+ const normalized = normalizeAdditionalVersionsToPrerelease(range);
104
+ return makeRange(normalized.replace(/==/g, '='), range);
105
+ }
106
+ //# sourceMappingURL=r-version.js.map
package/util/range.d.ts CHANGED
@@ -43,6 +43,10 @@ export declare function getRangeEnd(p: SourceRange | undefined): SourcePosition
43
43
  * @param ec - end column
44
44
  */
45
45
  export declare function rangeFrom(sl: number | string, sc: number | string, el: number | string, ec: number | string): SourceRange;
46
+ /**
47
+ * @returns an invalid source range
48
+ */
49
+ export declare function invalidRange(): SourceRange;
46
50
  /**
47
51
  * Merges multiple source ranges into a single source range that spans from the earliest start to the latest end.
48
52
  * If you are interested in combining overlapping ranges into a minimal set of ranges, see {@link combineRanges}.
@@ -75,3 +79,5 @@ export declare function rangeIsSubsetOf([r1sl, r1sc, r1el, r1ec]: SourceRange, [
75
79
  * If you are interested in merging overlapping ranges, see {@link mergeRanges}.
76
80
  */
77
81
  export declare function combineRanges(...ranges: SourceRange[]): SourceRange[];
82
+ /** A source location consisting of a source range and an optional file name. */
83
+ export type SourceLocation = [...r: SourceRange, f?: string];
package/util/range.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getRangeStart = getRangeStart;
4
4
  exports.getRangeEnd = getRangeEnd;
5
5
  exports.rangeFrom = rangeFrom;
6
+ exports.invalidRange = invalidRange;
6
7
  exports.mergeRanges = mergeRanges;
7
8
  exports.rangeStartsCompletelyBefore = rangeStartsCompletelyBefore;
8
9
  exports.rangesOverlap = rangesOverlap;
@@ -33,6 +34,12 @@ function getRangeEnd(p) {
33
34
  function rangeFrom(sl, sc, el, ec) {
34
35
  return [Number(sl), Number(sc), Number(el), Number(ec)];
35
36
  }
37
+ /**
38
+ * @returns an invalid source range
39
+ */
40
+ function invalidRange() {
41
+ return [-1, -1, -1, -1];
42
+ }
36
43
  /**
37
44
  * Merges multiple source ranges into a single source range that spans from the earliest start to the latest end.
38
45
  * If you are interested in combining overlapping ranges into a minimal set of ranges, see {@link combineRanges}.
@@ -88,8 +88,8 @@ function dfgToAscii(dfg) {
88
88
  }
89
89
  g.setNode(String(id), {
90
90
  label,
91
- width: Math.max(3, label.length * 2),
92
- height: 3,
91
+ width: Math.max(3, label.length * 1.2),
92
+ height: 4,
93
93
  shape: 'rectangle'
94
94
  });
95
95
  }
@@ -14,3 +14,12 @@
14
14
  * @param split - The character or character sequence to split on (can not be backslash or quote!)
15
15
  */
16
16
  export declare function splitAtEscapeSensitive(inputString: string, escapeQuote?: boolean, split?: RegExp | string): string[];
17
+ /**
18
+ * Splits the given string on 'and', but only if not nested inside `<>`, `[]`, `()`, or quotes.
19
+ * This also handles escaped quotes.
20
+ * @param str - The string to split
21
+ * @param splitOn - The string to split on (default: 'and')
22
+ * @param closes - The matching of closing characters for nesting, structures with different open and close characters only can be nested
23
+ * of each other, while those with the same open and close character (like quotes) can not be nested inside themselves.
24
+ */
25
+ export declare function splitOnNestingSensitive(str: string, splitOn?: string, closes?: Record<string, string>): string[];