@eagleoutice/flowr 2.1.11 → 2.1.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/README.md +1 -0
- package/cli/repl/commands/repl-query.js +1 -1
- package/cli/repl/server/connection.js +1 -1
- package/core/steps/pipeline/default-pipelines.d.ts +6 -0
- package/core/steps/pipeline/default-pipelines.js +6 -0
- package/dataflow/graph/vertex.d.ts +4 -0
- package/dataflow/graph/vertex.js +3 -1
- package/documentation/doc-util/doc-dfg.js +1 -1
- package/documentation/doc-util/doc-query.js +1 -1
- package/documentation/doc-util/doc-search.d.ts +25 -0
- package/documentation/doc-util/doc-search.js +121 -0
- package/documentation/doc-util/doc-types.d.ts +10 -2
- package/documentation/doc-util/doc-types.js +81 -3
- package/documentation/print-dataflow-graph-wiki.js +1 -1
- package/documentation/print-interface-wiki.js +24 -13
- package/documentation/print-normalized-ast-wiki.js +4 -4
- package/documentation/print-query-wiki.js +22 -0
- package/documentation/print-search-wiki.d.ts +1 -0
- package/documentation/print-search-wiki.js +74 -0
- package/package.json +2 -1
- package/queries/base-query-format.d.ts +2 -2
- package/queries/catalog/call-context-query/call-context-query-executor.d.ts +1 -1
- package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
- package/queries/catalog/cluster-query/cluster-query-executor.d.ts +1 -1
- package/queries/catalog/cluster-query/cluster-query-executor.js +1 -1
- package/queries/catalog/dataflow-query/dataflow-query-executor.d.ts +1 -1
- package/queries/catalog/dataflow-query/dataflow-query-executor.js +1 -1
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +2 -2
- package/queries/catalog/lineage-query/lineage-query-executor.d.ts +1 -1
- package/queries/catalog/lineage-query/lineage-query-executor.js +1 -1
- package/queries/catalog/search-query/search-query-executor.d.ts +3 -0
- package/queries/catalog/search-query/search-query-executor.js +27 -0
- package/queries/catalog/search-query/search-query-format.d.ts +72 -0
- package/queries/catalog/search-query/search-query-format.js +29 -0
- package/queries/catalog/static-slice-query/static-slice-query-executor.d.ts +1 -1
- package/queries/catalog/static-slice-query/static-slice-query-executor.js +1 -1
- package/queries/query.d.ts +59 -1
- package/queries/query.js +3 -1
- package/r-bridge/lang-4.x/ast/model/type.d.ts +4 -0
- package/r-bridge/lang-4.x/ast/model/type.js +3 -1
- package/search/flowr-search-builder.d.ts +193 -0
- package/search/flowr-search-builder.js +192 -0
- package/search/flowr-search-executor.d.ts +9 -0
- package/search/flowr-search-executor.js +16 -0
- package/search/flowr-search-filters.d.ts +74 -0
- package/search/flowr-search-filters.js +136 -0
- package/search/flowr-search-printer.d.ts +10 -0
- package/search/flowr-search-printer.js +85 -0
- package/search/flowr-search-traverse.d.ts +7 -0
- package/search/flowr-search-traverse.js +12 -0
- package/search/flowr-search.d.ts +58 -0
- package/search/flowr-search.js +29 -0
- package/search/search-executor/search-generators.d.ts +37 -0
- package/search/search-executor/search-generators.js +64 -0
- package/search/search-executor/search-transformer.d.ts +57 -0
- package/search/search-executor/search-transformer.js +99 -0
- package/search/search-optimizer/search-optimizer.d.ts +9 -0
- package/search/search-optimizer/search-optimizer.js +89 -0
- package/util/arrays.d.ts +13 -0
- package/util/assert.d.ts +1 -1
- package/util/mermaid/mermaid.js +17 -0
- package/util/version.js +1 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.flowrSearchToMermaid = flowrSearchToMermaid;
|
|
4
|
+
exports.flowrSearchToAscii = flowrSearchToAscii;
|
|
5
|
+
exports.flowrSearchToCode = flowrSearchToCode;
|
|
6
|
+
const flowr_search_traverse_1 = require("./flowr-search-traverse");
|
|
7
|
+
const mermaid_1 = require("../util/mermaid/mermaid");
|
|
8
|
+
const flowr_search_filters_1 = require("./flowr-search-filters");
|
|
9
|
+
const vertex_1 = require("../dataflow/graph/vertex");
|
|
10
|
+
const type_1 = require("../r-bridge/lang-4.x/ast/model/type");
|
|
11
|
+
/**
|
|
12
|
+
* Converts a {@link FlowrSearchLike} object to a mermaid flowchart.
|
|
13
|
+
*/
|
|
14
|
+
function flowrSearchToMermaid(search, conf) {
|
|
15
|
+
const out = [conf?.header ?? 'flowchart LR'];
|
|
16
|
+
let count = 0;
|
|
17
|
+
out.push((0, flowr_search_traverse_1.traverseFlowrSearchBuilderType)(search, ({ type, name, args }) => `${count}("<b>${name}</b>(${argsToMermaidString(args)})<br/>_${type}_")`, (acc, { name, args, type }) => `${acc} --> ${++count}["<b>${name}</b>(${argsToMermaidString(args)})<br/>_${type}_"]`));
|
|
18
|
+
return out.join('\n');
|
|
19
|
+
}
|
|
20
|
+
function argsToMermaidString(args) {
|
|
21
|
+
if (args === undefined) {
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
24
|
+
return Object.entries(args).map(([key, value]) => `${key}: ${(0, flowr_search_filters_1.isBinaryTree)(value) ? '_' + (0, mermaid_1.escapeMarkdown)((0, flowr_search_filters_1.binaryTreeToString)(value.tree)) + '_'
|
|
25
|
+
: (0, mermaid_1.escapeMarkdown)(JSON.stringify(value))}`)
|
|
26
|
+
.join(', ');
|
|
27
|
+
}
|
|
28
|
+
function argsToAsciiString(args) {
|
|
29
|
+
if (args === undefined) {
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
else if (Object.keys(args).length === 1) {
|
|
33
|
+
const key = Object.keys(args)[0];
|
|
34
|
+
const value = args[key];
|
|
35
|
+
return `${key}: ${(0, flowr_search_filters_1.isBinaryTree)(value) ? '_' + (0, flowr_search_filters_1.binaryTreeToString)(value.tree) + '_' : JSON.stringify(value)}`;
|
|
36
|
+
}
|
|
37
|
+
return Object.entries(args).map(([key, value]) => `${key}: ${(0, flowr_search_filters_1.isBinaryTree)(value) ? '_' + (0, flowr_search_filters_1.binaryTreeToString)(value.tree) + '_' : JSON.stringify(value)}`)
|
|
38
|
+
.join(', ');
|
|
39
|
+
}
|
|
40
|
+
function flowrSearchToAscii(search) {
|
|
41
|
+
return (0, flowr_search_traverse_1.traverseFlowrSearchBuilderType)(search, ({ name, args }) => `${name}(${argsToAsciiString(args)})`, (acc, { name, args }) => `${acc} --> ${name}(${argsToAsciiString(args)})`);
|
|
42
|
+
}
|
|
43
|
+
function argsToCodeString(args) {
|
|
44
|
+
if (args === undefined) {
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
return Object.entries(args).map(([, value]) => `${JSON.stringify(value)}`)
|
|
48
|
+
.join(', ');
|
|
49
|
+
}
|
|
50
|
+
function flowrSearchToCode(search) {
|
|
51
|
+
return (0, flowr_search_traverse_1.traverseFlowrSearchBuilderType)(search, (node) => `Q.${flowrGeneratorToCode(node)}`, (acc, node) => `${acc}.${flowrTransformerToCode(node)}`);
|
|
52
|
+
}
|
|
53
|
+
function flowrTransformerToCode(node) {
|
|
54
|
+
if (node.name === 'filter') {
|
|
55
|
+
const a = node.args.filter;
|
|
56
|
+
if (vertex_1.ValidVertexTypes.has(String(a))) {
|
|
57
|
+
return `${node.name}(VertexType.${vertex_1.ValidVertexTypeReverse[String(a)]})`;
|
|
58
|
+
}
|
|
59
|
+
else if (type_1.ValidRTypes.has(String(a))) {
|
|
60
|
+
return `${node.name}(RType.${type_1.ValidRTypesReverse[String(a)]})`;
|
|
61
|
+
}
|
|
62
|
+
else if (flowr_search_filters_1.ValidFlowrFilters.has(String(a))) {
|
|
63
|
+
return `${node.name}(FlowrFilter.${flowr_search_filters_1.ValidFlowrFiltersReverse[String(a)]})`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return `${node.name}(${argsToCodeString(node.args)})`;
|
|
67
|
+
}
|
|
68
|
+
function flowrGeneratorToCode(node) {
|
|
69
|
+
if (node.name !== 'get') {
|
|
70
|
+
return `${node.name}(${argsToCodeString(node.args)})`;
|
|
71
|
+
}
|
|
72
|
+
const a = node.args.filter;
|
|
73
|
+
if (Object.keys(a).length === 1) {
|
|
74
|
+
if (a.name) {
|
|
75
|
+
return `var(${JSON.stringify(a.name)})`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (Object.keys(a).length === 2) {
|
|
79
|
+
if (a.name && a.line) {
|
|
80
|
+
return `varInLine(${JSON.stringify(a.name)}, ${JSON.stringify(a.line)})`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return `${node.name}(${argsToCodeString(node.args)})`;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=flowr-search-printer.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FlowrSearchLike } from './flowr-search-builder';
|
|
2
|
+
import type { FlowrSearchGeneratorNode } from './search-executor/search-generators';
|
|
3
|
+
import type { FlowrSearchTransformerNode } from './search-executor/search-transformer';
|
|
4
|
+
/**
|
|
5
|
+
* Allows you to traverse a {@link FlowrSearchLike} object.
|
|
6
|
+
*/
|
|
7
|
+
export declare function traverseFlowrSearchBuilderType<Accumulate, GeneratorVisit extends (generator: FlowrSearchGeneratorNode) => Accumulate, TransformerVisit extends (acc: Accumulate, transformer: FlowrSearchTransformerNode) => Accumulate>(search: FlowrSearchLike, gen: GeneratorVisit, trans: TransformerVisit): Accumulate;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.traverseFlowrSearchBuilderType = traverseFlowrSearchBuilderType;
|
|
4
|
+
const flowr_search_builder_1 = require("./flowr-search-builder");
|
|
5
|
+
/**
|
|
6
|
+
* Allows you to traverse a {@link FlowrSearchLike} object.
|
|
7
|
+
*/
|
|
8
|
+
function traverseFlowrSearchBuilderType(search, gen, trans) {
|
|
9
|
+
const s = (0, flowr_search_builder_1.getFlowrSearch)(search);
|
|
10
|
+
return s.search.reduce(trans, gen(s.generator));
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=flowr-search-traverse.js.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { NoInfo, RNode } from '../r-bridge/lang-4.x/ast/model/model';
|
|
2
|
+
import type { Pipeline, PipelineOutput, PipelineStepOutputWithName } from '../core/steps/pipeline/pipeline';
|
|
3
|
+
import type { NormalizedAst } from '../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
+
import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
5
|
+
import type { DataflowInformation } from '../dataflow/info';
|
|
6
|
+
/**
|
|
7
|
+
* Yes, for now we do technically not need a wrapper around the RNode, but this allows us to attach caches etc.
|
|
8
|
+
* just for the respective search.
|
|
9
|
+
*/
|
|
10
|
+
export interface FlowrSearchElement<Info> {
|
|
11
|
+
readonly node: RNode<Info>;
|
|
12
|
+
}
|
|
13
|
+
export interface FlowrSearchNodeBase<Type extends string, Name extends string, Args extends Record<string, unknown> | undefined> {
|
|
14
|
+
readonly type: Type;
|
|
15
|
+
readonly name: Name;
|
|
16
|
+
readonly args: Args;
|
|
17
|
+
}
|
|
18
|
+
export type FlowrSearchGeneratorNodeBase<Name extends string, Args extends Record<string, unknown> | undefined> = FlowrSearchNodeBase<'generator', Name, Args>;
|
|
19
|
+
export type FlowrSearchTransformerNodeBase<Name extends string, Args extends Record<string, unknown> | undefined> = FlowrSearchNodeBase<'transformer', Name, Args>;
|
|
20
|
+
export interface FlowrSearchGetFilter extends Record<string, unknown> {
|
|
21
|
+
/**
|
|
22
|
+
* The node must be in the given line.
|
|
23
|
+
*/
|
|
24
|
+
readonly line?: number;
|
|
25
|
+
/**
|
|
26
|
+
* The node must be in the given column.
|
|
27
|
+
*/
|
|
28
|
+
readonly column?: number;
|
|
29
|
+
/**
|
|
30
|
+
* The node must have the given name.
|
|
31
|
+
* To treat this name as a regular expression, set {@link FlowrSearchGetFilter#nameIsRegex} to true.
|
|
32
|
+
*/
|
|
33
|
+
readonly name?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Only useful in combination with `name`. If true, the name is treated as a regular expression.
|
|
36
|
+
*/
|
|
37
|
+
readonly nameIsRegex?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* The node must have the given id.
|
|
40
|
+
*/
|
|
41
|
+
readonly id?: NodeId;
|
|
42
|
+
}
|
|
43
|
+
type MinimumInputForFlowrSearch<P extends Pipeline> = PipelineStepOutputWithName<P, 'normalize'> extends NormalizedAst ? (PipelineStepOutputWithName<P, 'dataflow'> extends DataflowInformation ? PipelineOutput<P> & {
|
|
44
|
+
normalize: NormalizedAst;
|
|
45
|
+
dataflow: DataflowInformation;
|
|
46
|
+
} : never) : never;
|
|
47
|
+
/** we allow any pipeline, which provides us with a 'normalize' and 'dataflow' step */
|
|
48
|
+
export type FlowrSearchInput<P extends Pipeline> = MinimumInputForFlowrSearch<P>;
|
|
49
|
+
/** Intentionally, we abstract away from an array to avoid the use of conventional typescript operations */
|
|
50
|
+
export declare class FlowrSearchElements<Info = NoInfo, Elements extends FlowrSearchElement<Info>[] = FlowrSearchElement<Info>[]> {
|
|
51
|
+
private elements;
|
|
52
|
+
constructor(elements?: Elements);
|
|
53
|
+
add(element: FlowrSearchElement<Info>): this;
|
|
54
|
+
addAll(elements: FlowrSearchElement<Info>[]): this;
|
|
55
|
+
getElements(): readonly FlowrSearchElement<Info>[];
|
|
56
|
+
mutate<OutElements extends Elements>(mutator: (elements: Elements) => OutElements): this;
|
|
57
|
+
}
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FlowrSearchElements = void 0;
|
|
4
|
+
/** Intentionally, we abstract away from an array to avoid the use of conventional typescript operations */
|
|
5
|
+
class FlowrSearchElements {
|
|
6
|
+
elements = [];
|
|
7
|
+
constructor(elements) {
|
|
8
|
+
if (elements) {
|
|
9
|
+
this.elements = elements;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
add(element) {
|
|
13
|
+
this.elements.push(element);
|
|
14
|
+
return this;
|
|
15
|
+
}
|
|
16
|
+
addAll(elements) {
|
|
17
|
+
this.elements.push(...elements);
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
getElements() {
|
|
21
|
+
return this.elements;
|
|
22
|
+
}
|
|
23
|
+
mutate(mutator) {
|
|
24
|
+
this.elements = mutator(this.elements);
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.FlowrSearchElements = FlowrSearchElements;
|
|
29
|
+
//# sourceMappingURL=flowr-search.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { FlowrSearchElement, FlowrSearchGeneratorNodeBase, FlowrSearchGetFilter, FlowrSearchInput } from '../flowr-search';
|
|
2
|
+
import { FlowrSearchElements } from '../flowr-search';
|
|
3
|
+
import type { Pipeline } from '../../core/steps/pipeline/pipeline';
|
|
4
|
+
import type { TailTypesOrUndefined } from '../../util/arrays';
|
|
5
|
+
import type { ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
6
|
+
import type { SlicingCriteria } from '../../slicing/criterion/parse';
|
|
7
|
+
/**
|
|
8
|
+
* This is a union of all possible generator node types
|
|
9
|
+
*/
|
|
10
|
+
export type FlowrSearchGeneratorNode = {
|
|
11
|
+
[K in GeneratorNames]: FlowrSearchGeneratorNodeBase<K, TailTypesOrUndefined<Parameters<typeof generators[K]>>>;
|
|
12
|
+
}[GeneratorNames];
|
|
13
|
+
export type GeneratorNames = keyof typeof generators;
|
|
14
|
+
export type GetGenerator<Name extends GeneratorNames> = FlowrSearchGeneratorNode & {
|
|
15
|
+
name: Name;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* All supported generators!
|
|
19
|
+
*/
|
|
20
|
+
export declare const generators: {
|
|
21
|
+
readonly all: typeof generateAll;
|
|
22
|
+
readonly get: typeof generateGet;
|
|
23
|
+
readonly criterion: typeof generateCriterion;
|
|
24
|
+
readonly from: typeof generateFrom;
|
|
25
|
+
};
|
|
26
|
+
declare function generateAll(data: FlowrSearchInput<Pipeline>): FlowrSearchElements<ParentInformation>;
|
|
27
|
+
declare function generateGet(data: FlowrSearchInput<Pipeline>, { filter: { line, column, id, name, nameIsRegex } }: {
|
|
28
|
+
filter: FlowrSearchGetFilter;
|
|
29
|
+
}): FlowrSearchElements<ParentInformation>;
|
|
30
|
+
declare function generateFrom(data: FlowrSearchInput<Pipeline>, args: {
|
|
31
|
+
from: FlowrSearchElement<ParentInformation> | FlowrSearchElement<ParentInformation>[];
|
|
32
|
+
}): FlowrSearchElements<ParentInformation>;
|
|
33
|
+
declare function generateCriterion(data: FlowrSearchInput<Pipeline>, args: {
|
|
34
|
+
criterion: SlicingCriteria;
|
|
35
|
+
}): FlowrSearchElements<ParentInformation>;
|
|
36
|
+
export declare function getGenerator<Name extends GeneratorNames>(name: Name): typeof generators[Name];
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generators = void 0;
|
|
4
|
+
exports.getGenerator = getGenerator;
|
|
5
|
+
const flowr_search_1 = require("../flowr-search");
|
|
6
|
+
const parse_1 = require("../../slicing/criterion/parse");
|
|
7
|
+
const assert_1 = require("../../util/assert");
|
|
8
|
+
/**
|
|
9
|
+
* All supported generators!
|
|
10
|
+
*/
|
|
11
|
+
exports.generators = {
|
|
12
|
+
all: generateAll,
|
|
13
|
+
get: generateGet,
|
|
14
|
+
criterion: generateCriterion,
|
|
15
|
+
from: generateFrom
|
|
16
|
+
};
|
|
17
|
+
function generateAll(data) {
|
|
18
|
+
return new flowr_search_1.FlowrSearchElements(getAllNodes(data)
|
|
19
|
+
.map(node => ({ node })));
|
|
20
|
+
}
|
|
21
|
+
function getAllNodes(data) {
|
|
22
|
+
return [...new Map([...data.normalize.idMap.values()].map(n => [n.info.id, n]))
|
|
23
|
+
.values()];
|
|
24
|
+
}
|
|
25
|
+
function generateGet(data, { filter: { line, column, id, name, nameIsRegex } }) {
|
|
26
|
+
let potentials = (id ?
|
|
27
|
+
[data.normalize.idMap.get(id)].filter(assert_1.isNotUndefined) :
|
|
28
|
+
getAllNodes(data));
|
|
29
|
+
if (line && line < 0) {
|
|
30
|
+
const maxLines = data.normalize.ast.info.fullRange?.[2] ??
|
|
31
|
+
(id ? getAllNodes(data) : potentials).reduce((maxLine, { location }) => location && location[2] > maxLine ? location[2] : maxLine, 0);
|
|
32
|
+
line = maxLines + line + 1;
|
|
33
|
+
}
|
|
34
|
+
if (line && column) {
|
|
35
|
+
potentials = potentials.filter(({ location }) => location?.[0] === line && location?.[1] === column);
|
|
36
|
+
}
|
|
37
|
+
else if (line) {
|
|
38
|
+
potentials = potentials.filter(({ location }) => location?.[0] === line);
|
|
39
|
+
}
|
|
40
|
+
else if (column) {
|
|
41
|
+
potentials = potentials.filter(({ location }) => location?.[1] === column);
|
|
42
|
+
}
|
|
43
|
+
if (nameIsRegex && name) {
|
|
44
|
+
const nameFilter = new RegExp(name);
|
|
45
|
+
potentials = potentials.filter(({ lexeme }) => lexeme && nameFilter.test(lexeme));
|
|
46
|
+
}
|
|
47
|
+
else if (name) {
|
|
48
|
+
potentials = potentials.filter(({ lexeme }) => lexeme === name);
|
|
49
|
+
}
|
|
50
|
+
return new flowr_search_1.FlowrSearchElements(potentials.map(node => ({ node })));
|
|
51
|
+
}
|
|
52
|
+
function generateFrom(data, args) {
|
|
53
|
+
return new flowr_search_1.FlowrSearchElements(Array.isArray(args.from) ? args.from : [args.from]);
|
|
54
|
+
}
|
|
55
|
+
function generateCriterion(data, args) {
|
|
56
|
+
return new flowr_search_1.FlowrSearchElements(args.criterion.map(c => ({ node: data.normalize.idMap.get((0, parse_1.slicingCriterionToId)(c, data.normalize.idMap)) })));
|
|
57
|
+
}
|
|
58
|
+
function getGenerator(name) {
|
|
59
|
+
if (!exports.generators[name]) {
|
|
60
|
+
throw new Error(`Unknown generator: ${name}`);
|
|
61
|
+
}
|
|
62
|
+
return exports.generators[name];
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=search-generators.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { FlowrSearchElement, FlowrSearchElements, FlowrSearchInput, FlowrSearchTransformerNodeBase } from '../flowr-search';
|
|
2
|
+
import type { Pipeline } from '../../core/steps/pipeline/pipeline';
|
|
3
|
+
import type { LastOfArray, Tail2TypesOrUndefined, TailOfArray } from '../../util/arrays';
|
|
4
|
+
import type { FlowrFilterExpression } from '../flowr-search-filters';
|
|
5
|
+
import type { FlowrSearchGeneratorNode } from './search-generators';
|
|
6
|
+
import type { ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
7
|
+
/**
|
|
8
|
+
* This is a union of all possible transformer node types
|
|
9
|
+
*/
|
|
10
|
+
export type FlowrSearchTransformerNode = {
|
|
11
|
+
[K in TransformerNames]: FlowrSearchTransformerNodeBase<K, Tail2TypesOrUndefined<Parameters<typeof transformers[K]>>>;
|
|
12
|
+
}[TransformerNames];
|
|
13
|
+
export type TransformerNames = keyof typeof transformers;
|
|
14
|
+
export type GetTransformer<Name extends TransformerNames> = FlowrSearchTransformerNode & {
|
|
15
|
+
name: Name;
|
|
16
|
+
};
|
|
17
|
+
export type GetOutputOfTransformer<Name extends TransformerNames> = ReturnType<typeof transformers[Name]>;
|
|
18
|
+
/**
|
|
19
|
+
* All supported generators!
|
|
20
|
+
*/
|
|
21
|
+
export declare const transformers: {
|
|
22
|
+
readonly first: typeof getFirst;
|
|
23
|
+
readonly last: typeof getLast;
|
|
24
|
+
readonly index: typeof getIndex;
|
|
25
|
+
readonly tail: typeof getTail;
|
|
26
|
+
readonly take: typeof getTake;
|
|
27
|
+
readonly skip: typeof getSkip;
|
|
28
|
+
readonly filter: typeof getFilter;
|
|
29
|
+
readonly merge: typeof getMerge;
|
|
30
|
+
readonly select: typeof getSelect;
|
|
31
|
+
};
|
|
32
|
+
export declare function getTransformer<Name extends TransformerNames>(name: Name): typeof transformers[Name];
|
|
33
|
+
/** If we already have no more elements, cascade will not add any but keep the empty elements, otherwise it will now be NewElements */
|
|
34
|
+
type CascadeEmpty<Elements extends FlowrSearchElement<ParentInformation>[], NewElements extends FlowrSearchElement<ParentInformation>[]> = Elements extends [] ? FlowrSearchElements<ParentInformation, []> : FlowrSearchElements<ParentInformation, NewElements>;
|
|
35
|
+
declare function getFirst<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE): CascadeEmpty<Elements, [Elements[0]]>;
|
|
36
|
+
declare function getLast<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE): CascadeEmpty<Elements, [LastOfArray<Elements>]>;
|
|
37
|
+
declare function getIndex<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE, { index }: {
|
|
38
|
+
index: number;
|
|
39
|
+
}): CascadeEmpty<Elements, [Elements[number]]>;
|
|
40
|
+
declare function getSelect<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE, { select }: {
|
|
41
|
+
select: number[];
|
|
42
|
+
}): CascadeEmpty<Elements, Elements>;
|
|
43
|
+
declare function getTail<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE): CascadeEmpty<Elements, TailOfArray<Elements>>;
|
|
44
|
+
declare function getTake<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE, { count }: {
|
|
45
|
+
count: number;
|
|
46
|
+
}): CascadeEmpty<Elements, TailOfArray<Elements>>;
|
|
47
|
+
declare function getSkip<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE, { count }: {
|
|
48
|
+
count: number;
|
|
49
|
+
}): CascadeEmpty<Elements, TailOfArray<Elements>>;
|
|
50
|
+
declare function getFilter<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE, { filter }: {
|
|
51
|
+
filter: FlowrFilterExpression;
|
|
52
|
+
}): CascadeEmpty<Elements, Elements | []>;
|
|
53
|
+
declare function getMerge<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE, other: {
|
|
54
|
+
search: unknown[];
|
|
55
|
+
generator: FlowrSearchGeneratorNode;
|
|
56
|
+
}): FlowrSearchElements<ParentInformation, FlowrSearchElement<ParentInformation>[]>;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.transformers = void 0;
|
|
4
|
+
exports.getTransformer = getTransformer;
|
|
5
|
+
const flowr_search_filters_1 = require("../flowr-search-filters");
|
|
6
|
+
const flowr_search_executor_1 = require("../flowr-search-executor");
|
|
7
|
+
const assert_1 = require("../../util/assert");
|
|
8
|
+
/**
|
|
9
|
+
* All supported generators!
|
|
10
|
+
*/
|
|
11
|
+
exports.transformers = {
|
|
12
|
+
first: getFirst,
|
|
13
|
+
last: getLast,
|
|
14
|
+
index: getIndex,
|
|
15
|
+
tail: getTail,
|
|
16
|
+
take: getTake,
|
|
17
|
+
skip: getSkip,
|
|
18
|
+
filter: getFilter,
|
|
19
|
+
merge: getMerge,
|
|
20
|
+
select: getSelect
|
|
21
|
+
};
|
|
22
|
+
function getTransformer(name) {
|
|
23
|
+
if (!exports.transformers[name]) {
|
|
24
|
+
throw new Error(`Unknown transformer: ${name}`);
|
|
25
|
+
}
|
|
26
|
+
return exports.transformers[name];
|
|
27
|
+
}
|
|
28
|
+
function compareByLocation({ node: a }, { node: b }) {
|
|
29
|
+
if (a.location && b.location) {
|
|
30
|
+
return a.location[0] - b.location[0] || a.location[1] - b.location[1];
|
|
31
|
+
}
|
|
32
|
+
else if (a.location) {
|
|
33
|
+
return -1;
|
|
34
|
+
}
|
|
35
|
+
return b.location ? 1 : 0;
|
|
36
|
+
}
|
|
37
|
+
function getFirstByLocation(elements) {
|
|
38
|
+
if (elements.length === 0) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return elements.reduce((acc, cur) => {
|
|
42
|
+
if (acc === undefined) {
|
|
43
|
+
return cur;
|
|
44
|
+
}
|
|
45
|
+
return compareByLocation(acc, cur) < 0 ? acc : cur;
|
|
46
|
+
}, undefined);
|
|
47
|
+
}
|
|
48
|
+
/* later we can add something like sort partially to get the first k elements */
|
|
49
|
+
function sortFully(elements) {
|
|
50
|
+
return elements.sort(compareByLocation);
|
|
51
|
+
}
|
|
52
|
+
function getLastByLocation(elements) {
|
|
53
|
+
if (elements.length === 0) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
return elements.reduce((acc, cur) => {
|
|
57
|
+
if (acc === undefined) {
|
|
58
|
+
return cur;
|
|
59
|
+
}
|
|
60
|
+
return compareByLocation(acc, cur) > 0 ? acc : cur;
|
|
61
|
+
}, undefined);
|
|
62
|
+
}
|
|
63
|
+
function getFirst(data, elements) {
|
|
64
|
+
return elements.mutate(e => [getFirstByLocation(e)]);
|
|
65
|
+
}
|
|
66
|
+
function getLast(data, elements) {
|
|
67
|
+
return elements.mutate(e => [getLastByLocation(e)]);
|
|
68
|
+
}
|
|
69
|
+
function getIndex(data, elements, { index }) {
|
|
70
|
+
return elements.mutate(e => [sortFully(e)[index]]);
|
|
71
|
+
}
|
|
72
|
+
function getSelect(data, elements, { select }) {
|
|
73
|
+
return elements.mutate(e => {
|
|
74
|
+
sortFully(e);
|
|
75
|
+
return select.map(i => e[i]).filter(assert_1.isNotUndefined);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function getTail(data, elements) {
|
|
79
|
+
return elements.mutate(e => {
|
|
80
|
+
const first = getFirstByLocation(e);
|
|
81
|
+
return e.filter(el => el !== first);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function getTake(data, elements, { count }) {
|
|
85
|
+
return elements.mutate(e => sortFully(e).slice(0, count));
|
|
86
|
+
}
|
|
87
|
+
function getSkip(data, elements, { count }) {
|
|
88
|
+
return elements.mutate(e => sortFully(e).slice(count));
|
|
89
|
+
}
|
|
90
|
+
function getFilter(data, elements, { filter }) {
|
|
91
|
+
return elements.mutate(e => e.filter(({ node }) => (0, flowr_search_filters_1.evalFilter)(filter, { node, normalize: data.normalize, dataflow: data.dataflow })));
|
|
92
|
+
}
|
|
93
|
+
function getMerge(
|
|
94
|
+
/* search has to be unknown because it is a recursive type */
|
|
95
|
+
data, elements, other) {
|
|
96
|
+
const resultOther = (0, flowr_search_executor_1.runSearch)(other, data);
|
|
97
|
+
return elements.addAll(resultOther);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=search-transformer.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FlowrSearchGeneratorNode, GeneratorNames } from '../search-executor/search-generators';
|
|
2
|
+
import type { FlowrSearchTransformerNode, TransformerNames } from '../search-executor/search-transformer';
|
|
3
|
+
import type { FlowrSearch } from '../flowr-search-builder';
|
|
4
|
+
import type { FlowrSearchElement, FlowrSearchElements } from '../flowr-search';
|
|
5
|
+
/**
|
|
6
|
+
* Optimizations are currently not reflected
|
|
7
|
+
* in an update of the search object.
|
|
8
|
+
*/
|
|
9
|
+
export declare function optimize<Info, Generator extends GeneratorNames, Transformers extends TransformerNames[], ElementType extends FlowrSearchElements<Info, FlowrSearchElement<Info>[]>>(generator: FlowrSearchGeneratorNode, search: readonly FlowrSearchTransformerNode[]): FlowrSearch<Info, Generator, Transformers, ElementType>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.optimize = optimize;
|
|
4
|
+
function fingerPrintTransformer(transformer) {
|
|
5
|
+
return JSON.stringify(transformer);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Optimizations are currently not reflected
|
|
9
|
+
* in an update of the search object.
|
|
10
|
+
*/
|
|
11
|
+
function optimize(generator, search) {
|
|
12
|
+
let searchToOptimize = search.slice();
|
|
13
|
+
let fingerprint = fingerPrintTransformer(searchToOptimize);
|
|
14
|
+
generator = optimizeGenerator(generator);
|
|
15
|
+
let lastFingerprint = '{}';
|
|
16
|
+
/* maybe we want shared optimizers in the future, but for now we let it be :sparkles: */
|
|
17
|
+
while (fingerprint !== lastFingerprint) {
|
|
18
|
+
lastFingerprint = fingerprint;
|
|
19
|
+
searchToOptimize = optimizeSearch(searchToOptimize, generator);
|
|
20
|
+
fingerprint = fingerPrintTransformer(searchToOptimize);
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
generator,
|
|
24
|
+
search: searchToOptimize
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function optimizeGenerator(generator) {
|
|
28
|
+
return dropAnyNameRegex(generator);
|
|
29
|
+
}
|
|
30
|
+
/*
|
|
31
|
+
* Ideas:
|
|
32
|
+
* Replace .tail().last() with .last()
|
|
33
|
+
* Replace .take(1) with '.first()'
|
|
34
|
+
* Remove duplicate indices in a .select
|
|
35
|
+
* Provide unification step after merge (id based)
|
|
36
|
+
* Install caches if sorting is required multiple times (especially for repeated use of generators)
|
|
37
|
+
*/
|
|
38
|
+
function optimizeSearch(search, _generator) {
|
|
39
|
+
search = dropDuplicateNoops(search);
|
|
40
|
+
search = selectWithSingleCanBeIndex(search);
|
|
41
|
+
return search;
|
|
42
|
+
}
|
|
43
|
+
const noopTransformers = new Set(['first', 'last']);
|
|
44
|
+
/* yes we could optimize something like first, last, first too, but why bother :D*/
|
|
45
|
+
function dropDuplicateNoops(transformers) {
|
|
46
|
+
const newTransformers = [];
|
|
47
|
+
let lastTransformer;
|
|
48
|
+
for (const transformer of transformers) {
|
|
49
|
+
if (lastTransformer === undefined || lastTransformer.name !== transformer.name || !noopTransformers.has(transformer.name)) {
|
|
50
|
+
newTransformers.push(transformer);
|
|
51
|
+
}
|
|
52
|
+
lastTransformer = transformer;
|
|
53
|
+
}
|
|
54
|
+
return newTransformers;
|
|
55
|
+
}
|
|
56
|
+
function selectWithSingleCanBeIndex(transformers) {
|
|
57
|
+
return transformers.map(transformer => {
|
|
58
|
+
if (transformer.name === 'select' && transformer.args.select.length === 1) {
|
|
59
|
+
return {
|
|
60
|
+
...transformer,
|
|
61
|
+
name: 'index',
|
|
62
|
+
args: {
|
|
63
|
+
index: transformer.args.select[0]
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return transformer;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function dropAnyNameRegex(generator) {
|
|
71
|
+
if (generator.name !== 'get' || !generator.args.filter.nameIsRegex) {
|
|
72
|
+
return generator;
|
|
73
|
+
}
|
|
74
|
+
if (generator.args.filter.name === '.') {
|
|
75
|
+
return {
|
|
76
|
+
...generator,
|
|
77
|
+
args: {
|
|
78
|
+
...generator.args,
|
|
79
|
+
filter: {
|
|
80
|
+
...generator.args.filter,
|
|
81
|
+
name: undefined,
|
|
82
|
+
nameIsRegex: undefined
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return generator;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=search-optimizer.js.map
|
package/util/arrays.d.ts
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
|
+
import type { AnyArray, Tail } from 'ts-essentials';
|
|
1
2
|
/**
|
|
2
3
|
* Returns the tail of an array (all elements except the first one).
|
|
3
4
|
*/
|
|
4
5
|
export type TailOfArray<T extends unknown[]> = T extends [infer _, ...infer Rest] ? Rest : never;
|
|
6
|
+
/**
|
|
7
|
+
* Returns the union of types in an array, but the first one, uses U as a fallback if the array is empty.
|
|
8
|
+
*/
|
|
9
|
+
export type TailTypesOrUndefined<T extends AnyArray, U = undefined> = T extends [] ? U : T extends [unknown] ? U : Tail<T>[number];
|
|
10
|
+
/**
|
|
11
|
+
* Returns the union of types in an array, but the first and the second one, uses U as a fallback if the array is empty.
|
|
12
|
+
*/
|
|
13
|
+
export type Tail2TypesOrUndefined<T extends AnyArray, U = undefined> = T extends [] ? U : T extends [unknown] ? U : T extends [unknown, unknown] ? U : Tail<Tail<T>>[number];
|
|
14
|
+
/**
|
|
15
|
+
* Returns the last element of an array
|
|
16
|
+
*/
|
|
17
|
+
export type LastOfArray<T extends AnyArray> = T extends [...infer _, infer L] ? L : never;
|
|
5
18
|
/**
|
|
6
19
|
* Splits the array every time the given predicate fires.
|
|
7
20
|
* The element the split appears on will not be included!
|
package/util/assert.d.ts
CHANGED
|
@@ -9,4 +9,4 @@ export type GuardMessage = string | (() => string);
|
|
|
9
9
|
* @param message - if a string, we will use it as the error message, if it is a function, we will call it to produce the error message (can be used to avoid costly message generations)
|
|
10
10
|
* @throws GuardError - if the assertion fails
|
|
11
11
|
*/
|
|
12
|
-
export declare function guard(assertion:
|
|
12
|
+
export declare function guard(assertion: unknown | undefined, message?: GuardMessage): asserts assertion;
|
package/util/mermaid/mermaid.js
CHANGED
|
@@ -21,6 +21,23 @@ const replacements = {
|
|
|
21
21
|
'&': '#38;',
|
|
22
22
|
'\'': '#39;',
|
|
23
23
|
':': '#58;',
|
|
24
|
+
'∨': '#8744;',
|
|
25
|
+
'∧': '#8743;',
|
|
26
|
+
'¬': '#172;',
|
|
27
|
+
'→': '#8594;',
|
|
28
|
+
'↔': '#8596;',
|
|
29
|
+
'⇒': '#8658;',
|
|
30
|
+
'⇔': '#8660;',
|
|
31
|
+
'∀': '#8704;',
|
|
32
|
+
'∃': '#8707;',
|
|
33
|
+
'∈': '#8712;',
|
|
34
|
+
'∉': '#8713;',
|
|
35
|
+
'∋': '#8715;',
|
|
36
|
+
'∌': '#8716;',
|
|
37
|
+
'∩': '#8745;',
|
|
38
|
+
'∪': '#8746;',
|
|
39
|
+
'∫': '#8747;',
|
|
40
|
+
'⊕': '#8853;',
|
|
24
41
|
};
|
|
25
42
|
function escapeMarkdown(text) {
|
|
26
43
|
for (const [key, value] of Object.entries(replacements)) {
|
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.1.
|
|
6
|
+
const version = '2.1.12';
|
|
7
7
|
function flowrVersion() {
|
|
8
8
|
return new semver_1.SemVer(version);
|
|
9
9
|
}
|