@eagleoutice/flowr 2.2.13 → 2.2.14
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 +4 -4
- package/cli/repl/commands/repl-cfg.d.ts +2 -2
- package/cli/repl/commands/repl-cfg.js +4 -4
- package/cli/repl/commands/repl-commands.js +2 -2
- package/cli/repl/server/connection.js +1 -1
- package/cli/script-core/statistics-helper-core.js +1 -1
- package/control-flow/extract-cfg.d.ts +2 -2
- package/control-flow/extract-cfg.js +10 -10
- package/documentation/doc-util/doc-cfg.d.ts +1 -1
- package/documentation/doc-util/doc-cfg.js +3 -3
- package/documentation/print-cfg-wiki.js +25 -25
- package/documentation/print-linter-wiki.d.ts +1 -0
- package/documentation/print-linter-wiki.js +76 -0
- package/linter/linter-executor.d.ts +9 -0
- package/linter/linter-executor.js +26 -0
- package/linter/linter-format.d.ts +65 -0
- package/linter/linter-format.js +9 -0
- package/linter/linter-rules.d.ts +42 -0
- package/linter/linter-rules.js +14 -0
- package/linter/rules/1-deprecated-functions.d.ts +34 -0
- package/linter/rules/1-deprecated-functions.js +54 -0
- package/linter/rules/2-file-path-validity.d.ts +48 -0
- package/linter/rules/2-file-path-validity.js +93 -0
- package/package.json +2 -1
- package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +2 -2
- package/queries/catalog/call-context-query/call-context-query-format.js +5 -1
- package/queries/catalog/cluster-query/cluster-query-format.d.ts +2 -0
- package/queries/catalog/cluster-query/cluster-query-format.js +5 -1
- package/queries/catalog/config-query/config-query-format.d.ts +1 -0
- package/queries/catalog/config-query/config-query-format.js +2 -1
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.d.ts +1 -0
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.js +2 -1
- package/queries/catalog/dataflow-query/dataflow-query-format.d.ts +2 -0
- package/queries/catalog/dataflow-query/dataflow-query-format.js +9 -1
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +1 -0
- package/queries/catalog/dependencies-query/dependencies-query-format.js +10 -1
- package/queries/catalog/happens-before-query/happens-before-query-format.d.ts +1 -0
- package/queries/catalog/happens-before-query/happens-before-query-format.js +2 -1
- package/queries/catalog/id-map-query/id-map-query-format.d.ts +1 -0
- package/queries/catalog/id-map-query/id-map-query-format.js +2 -1
- package/queries/catalog/lineage-query/lineage-query-format.d.ts +1 -0
- package/queries/catalog/lineage-query/lineage-query-format.js +5 -1
- package/queries/catalog/linter-query/linter-query-executor.d.ts +3 -0
- package/queries/catalog/linter-query/linter-query-executor.js +28 -0
- package/queries/catalog/linter-query/linter-query-format.d.ts +80 -0
- package/queries/catalog/linter-query/linter-query-format.js +43 -0
- package/queries/catalog/location-map-query/location-map-query-format.d.ts +1 -0
- package/queries/catalog/location-map-query/location-map-query-format.js +2 -1
- package/queries/catalog/normalized-ast-query/normalized-ast-query-format.d.ts +1 -0
- package/queries/catalog/normalized-ast-query/normalized-ast-query-format.js +2 -1
- package/queries/catalog/origin-query/origin-query-format.d.ts +2 -0
- package/queries/catalog/origin-query/origin-query-format.js +5 -1
- package/queries/catalog/project-query/project-query-executor.js +1 -1
- package/queries/catalog/project-query/project-query-format.d.ts +1 -0
- package/queries/catalog/project-query/project-query-format.js +2 -1
- package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +1 -0
- package/queries/catalog/resolve-value-query/resolve-value-query-format.js +2 -1
- package/queries/catalog/search-query/search-query-format.d.ts +1 -0
- package/queries/catalog/search-query/search-query-format.js +5 -1
- package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +2 -0
- package/queries/catalog/static-slice-query/static-slice-query-format.js +9 -1
- package/queries/query.d.ts +83 -1
- package/queries/query.js +2 -0
- package/r-bridge/retriever.js +1 -1
- package/search/flowr-search-builder.d.ts +31 -2
- package/search/flowr-search-builder.js +30 -0
- package/search/flowr-search.d.ts +7 -1
- package/search/search-executor/search-enrichers.d.ts +73 -0
- package/search/search-executor/search-enrichers.js +98 -0
- package/search/search-executor/search-generators.d.ts +6 -1
- package/search/search-executor/search-generators.js +21 -1
- package/search/search-executor/search-mappers.d.ts +19 -0
- package/search/search-executor/search-mappers.js +21 -0
- package/search/search-executor/search-transformer.d.ts +12 -0
- package/search/search-executor/search-transformer.js +11 -1
- package/util/version.js +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ It offers a wide variety of features, for example:
|
|
|
51
51
|
|
|
52
52
|
```shell
|
|
53
53
|
$ docker run -it --rm eagleoutice/flowr # or npm run flowr
|
|
54
|
-
flowR repl using flowR v2.2.
|
|
54
|
+
flowR repl using flowR v2.2.13, R v4.4.3 (r-shell engine)
|
|
55
55
|
R> :slicer test/testfiles/example.R --criterion "11@sum"
|
|
56
56
|
```
|
|
57
57
|
|
|
@@ -98,7 +98,7 @@ It offers a wide variety of features, for example:
|
|
|
98
98
|
|
|
99
99
|
|
|
100
100
|
* 🚀 **fast data- and control-flow graphs**\
|
|
101
|
-
Within just <i><span title="This measurement is automatically fetched from the latest benchmark!">
|
|
101
|
+
Within just <i><span title="This measurement is automatically fetched from the latest benchmark!">139.5 ms</span></i> (as of May 27, 2025),
|
|
102
102
|
_flowR_ can analyze the data- and control-flow of the average real-world R script. See the [benchmarks](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark) for more information,
|
|
103
103
|
and consult the [wiki pages](https://github.com/flowr-analysis/flowr/wiki/Dataflow-Graph) for more details on the dataflow graph.
|
|
104
104
|
|
|
@@ -134,7 +134,7 @@ It offers a wide variety of features, for example:
|
|
|
134
134
|
|
|
135
135
|
```shell
|
|
136
136
|
$ docker run -it --rm eagleoutice/flowr # or npm run flowr
|
|
137
|
-
flowR repl using flowR v2.2.
|
|
137
|
+
flowR repl using flowR v2.2.13, R v4.4.3 (r-shell engine)
|
|
138
138
|
R> :dataflow* test/testfiles/example.R
|
|
139
139
|
```
|
|
140
140
|
|
|
@@ -435,7 +435,7 @@ It offers a wide variety of features, for example:
|
|
|
435
435
|
```
|
|
436
436
|
|
|
437
437
|
|
|
438
|
-
(The analysis required _22.
|
|
438
|
+
(The analysis required _22.0 ms_ (including parse and normalize, using the [r-shell](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
|
|
439
439
|
|
|
440
440
|
|
|
441
441
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReplCommand } from './repl-main';
|
|
2
2
|
export declare const controlflowCommand: ReplCommand;
|
|
3
3
|
export declare const controlflowStarCommand: ReplCommand;
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
4
|
+
export declare const controlflowBbCommand: ReplCommand;
|
|
5
|
+
export declare const controlflowBbStarCommand: ReplCommand;
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
36
|
+
exports.controlflowBbStarCommand = exports.controlflowBbCommand = exports.controlflowStarCommand = exports.controlflowCommand = void 0;
|
|
37
37
|
const extract_cfg_1 = require("../../../control-flow/extract-cfg");
|
|
38
38
|
const default_pipelines_1 = require("../../../core/steps/pipeline/default-pipelines");
|
|
39
39
|
const retriever_1 = require("../../../r-bridge/retriever");
|
|
@@ -53,7 +53,7 @@ function formatInfo(out, type) {
|
|
|
53
53
|
}
|
|
54
54
|
async function produceAndPrintCfg(shell, remainingLine, output, simplifications, cfgConverter) {
|
|
55
55
|
const result = await controlflow(shell, handleString(remainingLine));
|
|
56
|
-
const cfg = (0, extract_cfg_1.
|
|
56
|
+
const cfg = (0, extract_cfg_1.extractCfg)(result.normalize, result.dataflow.graph, [...cfg_simplification_1.DefaultCfgSimplificationOrder, ...simplifications]);
|
|
57
57
|
const mermaid = cfgConverter(cfg, result.normalize);
|
|
58
58
|
output.stdout(mermaid);
|
|
59
59
|
try {
|
|
@@ -82,7 +82,7 @@ exports.controlflowStarCommand = {
|
|
|
82
82
|
await produceAndPrintCfg(shell, remainingLine, output, [], cfg_1.cfgToMermaidUrl);
|
|
83
83
|
}
|
|
84
84
|
};
|
|
85
|
-
exports.
|
|
85
|
+
exports.controlflowBbCommand = {
|
|
86
86
|
description: `Get mermaid code for the control-flow graph with basic blocks, start with '${retriever_1.fileProtocol}' to indicate a file`,
|
|
87
87
|
usageExample: ':controlflowbb',
|
|
88
88
|
aliases: ['cfgb', 'cfb'],
|
|
@@ -91,7 +91,7 @@ exports.controlflowBBCommand = {
|
|
|
91
91
|
await produceAndPrintCfg(shell, remainingLine, output, ['to-basic-blocks'], cfg_1.cfgToMermaid);
|
|
92
92
|
}
|
|
93
93
|
};
|
|
94
|
-
exports.
|
|
94
|
+
exports.controlflowBbStarCommand = {
|
|
95
95
|
description: 'Returns the URL to mermaid.live',
|
|
96
96
|
usageExample: ':controlflowbb*',
|
|
97
97
|
aliases: ['cfgb*', 'cfb*'],
|
|
@@ -85,8 +85,8 @@ const _commands = {
|
|
|
85
85
|
'dataflowsimple*': repl_dataflow_1.dataflowSimpleStarCommand,
|
|
86
86
|
'controlflow': repl_cfg_1.controlflowCommand,
|
|
87
87
|
'controlflow*': repl_cfg_1.controlflowStarCommand,
|
|
88
|
-
'controlflowbb': repl_cfg_1.
|
|
89
|
-
'controlflowbb*': repl_cfg_1.
|
|
88
|
+
'controlflowbb': repl_cfg_1.controlflowBbCommand,
|
|
89
|
+
'controlflowbb*': repl_cfg_1.controlflowBbStarCommand,
|
|
90
90
|
'lineage': repl_lineage_1.lineageCommand,
|
|
91
91
|
'query': repl_query_1.queryCommand,
|
|
92
92
|
'query*': repl_query_1.queryStarCommand
|
|
@@ -160,7 +160,7 @@ class FlowRServerConnection {
|
|
|
160
160
|
async sendFileAnalysisResponse(slicer, results, message) {
|
|
161
161
|
let cfg = undefined;
|
|
162
162
|
if (message.cfg) {
|
|
163
|
-
cfg = (0, extract_cfg_1.
|
|
163
|
+
cfg = (0, extract_cfg_1.extractCfg)(results.normalize, results.dataflow?.graph);
|
|
164
164
|
}
|
|
165
165
|
const config = () => ({ context: message.filename ?? 'unknown', getId: (0, quads_1.defaultQuadIdGenerator)() });
|
|
166
166
|
const sanitizedResults = sanitizeAnalysisResults(results);
|
|
@@ -58,7 +58,7 @@ async function getStatsForSingleFile(options) {
|
|
|
58
58
|
if (stats.outputs.size === 1) {
|
|
59
59
|
if (options['dump-json']) {
|
|
60
60
|
const [, output] = [...stats.outputs.entries()][0];
|
|
61
|
-
const cfg = (0, extract_cfg_1.
|
|
61
|
+
const cfg = (0, extract_cfg_1.extractCfg)(output.normalize, output.dataflow.graph);
|
|
62
62
|
statistics_file_1.statisticsFileProvider.append('output-json', 'parse', await (0, print_1.printStepResult)(_00_parse_1.PARSE_WITH_R_SHELL_STEP, output.parse, 2 /* StepOutputFormat.Json */));
|
|
63
63
|
statistics_file_1.statisticsFileProvider.append('output-json', 'normalize', await (0, print_1.printStepResult)(_10_normalize_1.NORMALIZE, output.normalize, 2 /* StepOutputFormat.Json */));
|
|
64
64
|
statistics_file_1.statisticsFileProvider.append('output-json', 'dataflow', await (0, print_1.printStepResult)(_20_dataflow_1.STATIC_DATAFLOW, output.dataflow, 2 /* StepOutputFormat.Json */));
|
|
@@ -14,9 +14,9 @@ import type { CfgSimplificationPassName } from './cfg-simplification';
|
|
|
14
14
|
*
|
|
15
15
|
* @see {@link extractSimpleCfg} - for a simplified version of this function
|
|
16
16
|
*/
|
|
17
|
-
export declare function
|
|
17
|
+
export declare function extractCfg<Info = ParentInformation>(ast: NormalizedAst<Info>, graph?: DataflowGraph, simplifications?: readonly CfgSimplificationPassName[]): ControlFlowInformation;
|
|
18
18
|
/**
|
|
19
|
-
* Simplified version of {@link
|
|
19
|
+
* Simplified version of {@link extractCfg} that is much quicker, but much simpler!
|
|
20
20
|
*/
|
|
21
21
|
export declare function extractSimpleCfg<Info = ParentInformation>(ast: NormalizedAst<Info>): ControlFlowInformation<import("./control-flow-graph").CfgSimpleVertex>;
|
|
22
22
|
export declare const ResolvedCallSuffix = "-resolved-call-exit";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ResolvedCallSuffix = void 0;
|
|
4
|
-
exports.
|
|
4
|
+
exports.extractCfg = extractCfg;
|
|
5
5
|
exports.extractSimpleCfg = extractSimpleCfg;
|
|
6
6
|
exports.cfg2quads = cfg2quads;
|
|
7
7
|
const quads_1 = require("../util/quads");
|
|
@@ -62,11 +62,11 @@ function dataflowCfgFolds(dataflowGraph) {
|
|
|
62
62
|
*
|
|
63
63
|
* @see {@link extractSimpleCfg} - for a simplified version of this function
|
|
64
64
|
*/
|
|
65
|
-
function
|
|
65
|
+
function extractCfg(ast, graph, simplifications) {
|
|
66
66
|
return (0, cfg_simplification_1.simplifyControlFlowInformation)((0, fold_1.foldAst)(ast.ast, graph ? dataflowCfgFolds(graph) : cfgFolds), simplifications);
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
-
* Simplified version of {@link
|
|
69
|
+
* Simplified version of {@link extractCfg} that is much quicker, but much simpler!
|
|
70
70
|
*/
|
|
71
71
|
function extractSimpleCfg(ast) {
|
|
72
72
|
return (0, fold_1.foldAst)(ast.ast, cfgFolds);
|
|
@@ -272,11 +272,11 @@ function cfgFunctionCall(call, name, args, exit = 'exit') {
|
|
|
272
272
|
exports.ResolvedCallSuffix = '-resolved-call-exit';
|
|
273
273
|
function cfgFunctionCallWithDataflow(graph) {
|
|
274
274
|
return (call, name, args) => {
|
|
275
|
-
const
|
|
275
|
+
const baseCfg = cfgFunctionCall(call, name, args);
|
|
276
276
|
/* try to resolve the call and link the target definitions */
|
|
277
277
|
const targets = (0, linker_1.getAllFunctionCallTargets)(call.info.id, graph);
|
|
278
278
|
const exits = [];
|
|
279
|
-
const callVertex =
|
|
279
|
+
const callVertex = baseCfg.graph.getVertex(call.info.id);
|
|
280
280
|
(0, assert_1.guard)(callVertex !== undefined, 'cfgFunctionCallWithDataflow: call vertex not found');
|
|
281
281
|
for (const target of targets) {
|
|
282
282
|
// we have to filter out non func-call targets as the call targets contains names and call ids
|
|
@@ -287,21 +287,21 @@ function cfgFunctionCallWithDataflow(graph) {
|
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
if (exits.length > 0) {
|
|
290
|
-
|
|
290
|
+
baseCfg.graph.addVertex({
|
|
291
291
|
id: call.info.id + exports.ResolvedCallSuffix,
|
|
292
292
|
type: control_flow_graph_1.CfgVertexType.EndMarker,
|
|
293
293
|
root: call.info.id
|
|
294
294
|
});
|
|
295
|
-
for (const exit of [...
|
|
296
|
-
|
|
295
|
+
for (const exit of [...baseCfg.exitPoints, ...exits]) {
|
|
296
|
+
baseCfg.graph.addEdge(call.info.id + exports.ResolvedCallSuffix, exit, { label: 0 /* CfgEdgeType.Fd */ });
|
|
297
297
|
}
|
|
298
298
|
return {
|
|
299
|
-
...
|
|
299
|
+
...baseCfg,
|
|
300
300
|
exitPoints: [call.info.id + exports.ResolvedCallSuffix]
|
|
301
301
|
};
|
|
302
302
|
}
|
|
303
303
|
else {
|
|
304
|
-
return
|
|
304
|
+
return baseCfg;
|
|
305
305
|
}
|
|
306
306
|
};
|
|
307
307
|
}
|
|
@@ -19,5 +19,5 @@ export interface PrintCfgOptions {
|
|
|
19
19
|
readonly simplify?: boolean;
|
|
20
20
|
readonly useDfg?: boolean;
|
|
21
21
|
}
|
|
22
|
-
export declare function
|
|
22
|
+
export declare function printCfgCode(parser: KnownParser, code: string, { showCode, openCode, prefix, simplifications, simplify, useDfg }?: PrintCfgOptions): Promise<string>;
|
|
23
23
|
export {};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getCfg = getCfg;
|
|
4
4
|
exports.printCfg = printCfg;
|
|
5
|
-
exports.
|
|
5
|
+
exports.printCfgCode = printCfgCode;
|
|
6
6
|
const extract_cfg_1 = require("../../control-flow/extract-cfg");
|
|
7
7
|
const default_pipelines_1 = require("../../core/steps/pipeline/default-pipelines");
|
|
8
8
|
const retriever_1 = require("../../r-bridge/retriever");
|
|
@@ -17,7 +17,7 @@ async function getCfg(parser, code, simplifications = [], useDfg = true) {
|
|
|
17
17
|
}).allRemainingSteps() : await (0, default_pipelines_1.createNormalizePipeline)(parser, {
|
|
18
18
|
request: (0, retriever_1.requestFromInput)(code)
|
|
19
19
|
}).allRemainingSteps();
|
|
20
|
-
const cfg = (0, extract_cfg_1.
|
|
20
|
+
const cfg = (0, extract_cfg_1.extractCfg)(result.normalize, useDfg ? result.dataflow.graph : undefined, [...cfg_simplification_1.DefaultCfgSimplificationOrder, ...simplifications]);
|
|
21
21
|
return {
|
|
22
22
|
info: cfg,
|
|
23
23
|
ast: result.normalize,
|
|
@@ -29,7 +29,7 @@ function printCfg(cfg, ast, prefix = 'flowchart BT\n', simplify = false) {
|
|
|
29
29
|
${(0, doc_code_1.codeBlock)('mermaid', (0, cfg_1.cfgToMermaid)(cfg, ast, prefix, simplify))}
|
|
30
30
|
`;
|
|
31
31
|
}
|
|
32
|
-
async function
|
|
32
|
+
async function printCfgCode(parser, code, { showCode = true, openCode = false, prefix = 'flowchart BT\n', simplifications = [], simplify = false, useDfg = true } = {}) {
|
|
33
33
|
const now = performance.now();
|
|
34
34
|
const res = await getCfg(parser, code, simplifications, useDfg);
|
|
35
35
|
const duration = performance.now() - now;
|
|
@@ -167,7 +167,7 @@ ${(0, doc_code_1.codeBlock)('r', 'x <- 2 * 3 + 1')}
|
|
|
167
167
|
|
|
168
168
|
The corresponding CFG is a directed, labeled graph with two types of edges (control and flow dependencies).
|
|
169
169
|
|
|
170
|
-
${await (0, doc_cfg_1.
|
|
170
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n' })}
|
|
171
171
|
|
|
172
172
|
${(0, doc_structure_1.block)({
|
|
173
173
|
type: 'IMPORTANT',
|
|
@@ -180,30 +180,30 @@ Expressions, such as \`2 * 3\` get an additional node with an artificial id that
|
|
|
180
180
|
|
|
181
181
|
To gain a better understanding, let's have a look at a simple program with a single branching structure:
|
|
182
182
|
|
|
183
|
-
${await (0, doc_cfg_1.
|
|
183
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'if(u) 3 else 2', { showCode: true, openCode: false, prefix: 'flowchart RL\n' })}
|
|
184
184
|
|
|
185
185
|
Here, you can see the \`if\` node followed by the condition (in this case merely \`u\`) that then splits into two branches for the two possible outcomes.
|
|
186
186
|
The \`if\` structure is terminated by the corresponding \`-exit\` node (see the [structure](#cfg-structure) section for more details).
|
|
187
187
|
|
|
188
188
|
For you to compare, the following shows the CFG of an \`if\` without an \`else\` branch:
|
|
189
189
|
|
|
190
|
-
${await (0, doc_cfg_1.
|
|
190
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n' })}
|
|
191
191
|
|
|
192
192
|
Activating the calculation of basic blocks produces the following:
|
|
193
193
|
|
|
194
|
-
${await (0, doc_cfg_1.
|
|
194
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'] })}
|
|
195
195
|
|
|
196
196
|
Which is probably much more readable if compacted (although the reconstucted code can sometimes be slightly mislieading as flowR tries its best to make it syntactically correct and hence add closing braces etc. which are technically not part of the respective block):
|
|
197
197
|
|
|
198
|
-
${await (0, doc_cfg_1.
|
|
198
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: true })}
|
|
199
199
|
|
|
200
200
|
The control flow graph also harmonizes with function definitions, and calls:
|
|
201
201
|
|
|
202
|
-
${await (0, doc_cfg_1.
|
|
202
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'f <- function() { 3 }\nf()', { showCode: true, openCode: true, prefix: 'flowchart RL\n' })}
|
|
203
203
|
|
|
204
204
|
${(0, doc_structure_1.section)('Structure of the Control Flow Graph', 2, 'cfg-structure')}
|
|
205
205
|
|
|
206
|
-
You can produce your very own control flow graph with ${(0, doc_types_1.shortLink)(extract_cfg_1.
|
|
206
|
+
You can produce your very own control flow graph with ${(0, doc_types_1.shortLink)(extract_cfg_1.extractCfg.name, types.info)}.
|
|
207
207
|
The ${(0, doc_types_1.shortLink)(control_flow_graph_1.ControlFlowGraph.name, types.info)} class describes everything required to model the control flow graph, with its edge types described by
|
|
208
208
|
${(0, doc_types_1.shortLink)('CfgEdge', types.info)} and its vertices by ${(0, doc_types_1.shortLink)('CfgSimpleVertex', types.info)}.
|
|
209
209
|
However, you should be aware of the ${(0, doc_types_1.shortLink)('ControlFlowInformation', types.info)} interface which adds some additional information the the CFG
|
|
@@ -214,7 +214,7 @@ ${(0, doc_types_1.printHierarchy)({ info: types.info, root: 'ControlFlowInformat
|
|
|
214
214
|
To check whether the CFG has the expected shape, you can use the test function ${(0, doc_types_1.shortLink)('assertCfg', testTypes.info)} which supports testing for
|
|
215
215
|
sub-graphs as well (it provides diffing capabilities similar to ${(0, doc_types_1.shortLink)('assertDataflow', testTypes.info)}).
|
|
216
216
|
As the CFG may become unhandy for larger programs, there are simplifications available with ${(0, doc_types_1.shortLink)(cfg_simplification_1.simplifyControlFlowInformation.name, types.info)}
|
|
217
|
-
(these can be passed on to the ${(0, doc_types_1.shortLink)(extract_cfg_1.
|
|
217
|
+
(these can be passed on to the ${(0, doc_types_1.shortLink)(extract_cfg_1.extractCfg.name, types.info)} function as well).
|
|
218
218
|
|
|
219
219
|
${(0, doc_structure_1.section)('CFG Vertices', 3, 'cfg-structure-vertices')}
|
|
220
220
|
|
|
@@ -258,7 +258,7 @@ ${(0, doc_structure_1.section)('Flow Dependencies', 4, 'cfg-flow-dependency')}
|
|
|
258
258
|
The most common edge is the flow dependency (FD) which simply signals that the source vertex happens _after_ the target vertex in the control flow.
|
|
259
259
|
So \`x; y\` would produce a flow dependency from \`y\` to \`x\` (additionally to the program-enveloping root expression list):
|
|
260
260
|
|
|
261
|
-
${await (0, doc_cfg_1.
|
|
261
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'x; y', { showCode: false, prefix: 'flowchart RL\n' })}
|
|
262
262
|
|
|
263
263
|
${(0, doc_structure_1.section)('Control Dependencies', 4, 'cfg-control-dependency')}
|
|
264
264
|
|
|
@@ -271,12 +271,12 @@ The extra \`caused\` link signals the vertex that caused the control flow influe
|
|
|
271
271
|
|
|
272
272
|
|
|
273
273
|
${await (async () => {
|
|
274
|
-
const exa = await (0, doc_cfg_1.
|
|
274
|
+
const exa = await (0, doc_cfg_1.printCfgCode)(shell, 'if(u) 3 else 2', { showCode: true, prefix: 'flowchart RL\n' });
|
|
275
275
|
return (0, doc_structure_1.details)('Example: if-else', exa);
|
|
276
276
|
})()}
|
|
277
277
|
|
|
278
278
|
${await (async () => {
|
|
279
|
-
const exa = await (0, doc_cfg_1.
|
|
279
|
+
const exa = await (0, doc_cfg_1.printCfgCode)(shell, 'while(u) b', { showCode: true, prefix: 'flowchart RL\n' });
|
|
280
280
|
return (0, doc_structure_1.details)('Example: while-loop', exa);
|
|
281
281
|
})()}
|
|
282
282
|
<br/>
|
|
@@ -286,12 +286,12 @@ Additionally, the control flow graph does not have to be connected. If you use a
|
|
|
286
286
|
the corresponding exit markers are not reachable from the entry:
|
|
287
287
|
|
|
288
288
|
${await (async () => {
|
|
289
|
-
const exa = await (0, doc_cfg_1.
|
|
289
|
+
const exa = await (0, doc_cfg_1.printCfgCode)(shell, 'repeat { b }; after', { showCode: true, prefix: 'flowchart RL\n' });
|
|
290
290
|
return (0, doc_structure_1.details)('Example: repeat-loop (infinite)', exa);
|
|
291
291
|
})()}
|
|
292
292
|
|
|
293
293
|
${await (async () => {
|
|
294
|
-
const exa = await (0, doc_cfg_1.
|
|
294
|
+
const exa = await (0, doc_cfg_1.printCfgCode)(shell, 'repeat { b; if(u) break; }; after', { showCode: true, prefix: 'flowchart RL\n' });
|
|
295
295
|
return (0, doc_structure_1.details)('Example: repeat-loop (with break)', exa);
|
|
296
296
|
})()}
|
|
297
297
|
<br/>
|
|
@@ -299,22 +299,22 @@ ${await (async () => {
|
|
|
299
299
|
In the context of a for-loop, the control dependency refer to whether the respective vector still has values to iterate over.
|
|
300
300
|
|
|
301
301
|
${await (async () => {
|
|
302
|
-
const exa = await (0, doc_cfg_1.
|
|
302
|
+
const exa = await (0, doc_cfg_1.printCfgCode)(shell, 'for(i in 1:10) b', { showCode: true, prefix: 'flowchart RL\n' });
|
|
303
303
|
return (0, doc_structure_1.details)('Example: for-loop', exa);
|
|
304
304
|
})()}
|
|
305
305
|
|
|
306
306
|
${(0, doc_structure_1.section)('Extra: Call Links', 4, 'cfg-call-links')}
|
|
307
307
|
|
|
308
|
-
If you generate the CFG with the ${(0, doc_types_1.shortLink)(extract_cfg_1.
|
|
308
|
+
If you generate the CFG with the ${(0, doc_types_1.shortLink)(extract_cfg_1.extractCfg.name, types.info)} function you can (and, if you want to gain inter-procedural information, should)
|
|
309
309
|
pass a matching [dataflow graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph) to it to incorporate the dataflow perspective into the CFG.
|
|
310
310
|
|
|
311
311
|
The difference becomes obvious when we look at the code \`f <- function() b; f()\` first without the dataflow graph:
|
|
312
312
|
|
|
313
|
-
${await (0, doc_cfg_1.
|
|
313
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'f <- function() b; f()', { showCode: true, prefix: 'flowchart RL\n', useDfg: false })}
|
|
314
314
|
|
|
315
315
|
And now, including dataflow information:
|
|
316
316
|
|
|
317
|
-
${await (0, doc_cfg_1.
|
|
317
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'f <- function() b; f()', { showCode: true, prefix: 'flowchart RL\n', useDfg: true })}
|
|
318
318
|
|
|
319
319
|
There are two important additions:
|
|
320
320
|
|
|
@@ -325,7 +325,7 @@ There are two important additions:
|
|
|
325
325
|
For built-in functions that are provided by flowR's built-in configuration (see the [interface wiki page](${doc_files_1.FlowrWikiBaseRef}/Interface)) the CFG does not contain
|
|
326
326
|
the additional information directly:
|
|
327
327
|
|
|
328
|
-
${await (0, doc_cfg_1.
|
|
328
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'print(3)', { showCode: true, prefix: 'flowchart RL\n' })}
|
|
329
329
|
|
|
330
330
|
This is due to the fact that the [dataflow graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph) does contain the required call information (and there are no new control vertices to add as the built-in call has no target in the source code):
|
|
331
331
|
|
|
@@ -340,16 +340,16 @@ Yet, we can request basic blocks or transform an existing CFG into basic blocks
|
|
|
340
340
|
|
|
341
341
|
Any program without any (un-)conditional jumps now contains a single basic block:
|
|
342
342
|
|
|
343
|
-
${await (0, doc_cfg_1.
|
|
343
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'x <- 2 * 3 + 1', { showCode: true, openCode: true, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: true })}
|
|
344
344
|
|
|
345
345
|
While the CFG without basic blocks is much bigger:
|
|
346
346
|
|
|
347
|
-
${await (0, doc_cfg_1.
|
|
347
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n' })}
|
|
348
348
|
|
|
349
349
|
In a way, using the basic blocks perspective does not remove any of these vertices (we just usually visualize them compacted as their execution order should be "obvious").
|
|
350
350
|
The vertices are still there, as elems of the ${(0, doc_types_1.shortLink)('CfgBasicBlockVertex', types.info)}:
|
|
351
351
|
|
|
352
|
-
${await (0, doc_cfg_1.
|
|
352
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: false })}
|
|
353
353
|
|
|
354
354
|
The benefit (for comprehensibility and algorithms) becomes more apparent when we look at a more complicated program:
|
|
355
355
|
|
|
@@ -357,12 +357,12 @@ ${(0, doc_code_1.codeBlock)('r', CfgLongExample)}
|
|
|
357
357
|
|
|
358
358
|
With basic blocks, this code looks like this:
|
|
359
359
|
|
|
360
|
-
${await (0, doc_cfg_1.
|
|
360
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, CfgLongExample, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: true })}
|
|
361
361
|
|
|
362
362
|
Now, without basic blocks, this is a different story...
|
|
363
363
|
|
|
364
364
|
${await (async () => {
|
|
365
|
-
const exa = await (0, doc_cfg_1.
|
|
365
|
+
const exa = await (0, doc_cfg_1.printCfgCode)(shell, CfgLongExample, { showCode: false, prefix: 'flowchart RL\n' });
|
|
366
366
|
return (0, doc_structure_1.details)('The full CFG', exa);
|
|
367
367
|
})()}
|
|
368
368
|
|
|
@@ -529,7 +529,7 @@ ${await (async function () {
|
|
|
529
529
|
(0, assert_1.guard)(plusVertex.type === control_flow_graph_1.CfgVertexType.Expression);
|
|
530
530
|
const numOfExits = plusVertex.end?.length ?? 0;
|
|
531
531
|
(0, assert_1.guard)(plusVertex.end && numOfExits === 1);
|
|
532
|
-
return `${await (0, doc_cfg_1.
|
|
532
|
+
return `${await (0, doc_cfg_1.printCfgCode)(shell, 'x + 1', { showCode: true, prefix: 'flowchart RL\n' })}
|
|
533
533
|
|
|
534
534
|
Looking at the binary operation vertex for \`+\` (with id \`${plusVertexId}\`) we see that it is linked to a single exit ("end marker") point: \`${plusVertex.end[0]}\`.
|
|
535
535
|
Checking this vertex essentially reveals all exit points of the expression ‐ in this case, this simply refers to the operands of the addition.
|
|
@@ -544,7 +544,7 @@ ${(0, doc_structure_1.details)('Example: Exit Points for an if', await (async fu
|
|
|
544
544
|
(0, assert_1.guard)(ifVertex.type === control_flow_graph_1.CfgVertexType.Statement);
|
|
545
545
|
const numOfExits = ifVertex.end?.length ?? 0;
|
|
546
546
|
(0, assert_1.guard)(ifVertex.end && numOfExits === 1);
|
|
547
|
-
return `${await (0, doc_cfg_1.
|
|
547
|
+
return `${await (0, doc_cfg_1.printCfgCode)(shell, expr, { showCode: true, prefix: 'flowchart RL\n' })}
|
|
548
548
|
|
|
549
549
|
Looking at the if vertex for (with id \`${ifVertexId}\`) we see that it is again linked to a single exit point: \`${ifVertex.end[0]}\`.
|
|
550
550
|
Yet, now this exit vertex is linked to the two branches of the if statement (the \`then\` and \`else\` branch).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const log_1 = require("../../test/functionality/_helper/log");
|
|
7
|
+
const doc_auto_gen_1 = require("./doc-util/doc-auto-gen");
|
|
8
|
+
const doc_files_1 = require("./doc-util/doc-files");
|
|
9
|
+
const linter_rules_1 = require("../linter/linter-rules");
|
|
10
|
+
const doc_code_1 = require("./doc-util/doc-code");
|
|
11
|
+
const shell_1 = require("../r-bridge/shell");
|
|
12
|
+
const doc_query_1 = require("./doc-util/doc-query");
|
|
13
|
+
const doc_types_1 = require("./doc-util/doc-types");
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
async function getText(shell) {
|
|
16
|
+
const rVersion = (await shell.usedRVersion())?.format() ?? 'unknown';
|
|
17
|
+
return `${(0, doc_auto_gen_1.autoGenHeader)({ filename: module.filename, purpose: 'linter', rVersion })}
|
|
18
|
+
|
|
19
|
+
This page describes the flowR linter, which is a tool that utilizes flowR's dataflow analysis to find common issues in R scripts. The linter can currently be used through the linter [query](${doc_files_1.FlowrWikiBaseRef}/Query%20API).
|
|
20
|
+
|
|
21
|
+
## Linting Rules
|
|
22
|
+
|
|
23
|
+
The following linting rules are available:
|
|
24
|
+
|
|
25
|
+
${await rule(shell, 'deprecated-functions', 'DeprecatedFunctionsConfig', 'Deprecated Functions', 'This rule detects the usage of deprecated functions in code based on a predefined list of known deprecated functions.', `
|
|
26
|
+
first <- data.frame(x = c(1, 2, 3), y = c(1, 2, 3))
|
|
27
|
+
second <- data.frame(x = c(1, 3, 2), y = c(1, 3, 2))
|
|
28
|
+
dplyr::all_equal(first, second)
|
|
29
|
+
`)}
|
|
30
|
+
|
|
31
|
+
${await rule(shell, 'file-path-validity', 'FilePathValidityConfig', 'File Path Validity', 'This rule finds places in the code where files are being read from. In such places, it checks whether the file path is valid and whether the file exists on disk.', `
|
|
32
|
+
my_data <- read.csv("C:/Users/me/Documents/My R Scripts/Reproducible.csv")
|
|
33
|
+
`)}
|
|
34
|
+
|
|
35
|
+
`.trim();
|
|
36
|
+
}
|
|
37
|
+
async function rule(shell, name, configType, friendlyName, description, example) {
|
|
38
|
+
const types = (0, doc_types_1.getTypesFromFolderAsMermaid)({
|
|
39
|
+
rootFolder: path_1.default.resolve('./src/linter/'),
|
|
40
|
+
typeName: configType,
|
|
41
|
+
inlineTypes: doc_types_1.mermaidHide
|
|
42
|
+
});
|
|
43
|
+
return `
|
|
44
|
+
### ${friendlyName} (\`${name}\`)
|
|
45
|
+
|
|
46
|
+
${description}
|
|
47
|
+
|
|
48
|
+
<details>
|
|
49
|
+
|
|
50
|
+
#### Configuration
|
|
51
|
+
|
|
52
|
+
Linting rules can be configured by passing a configuration object to the linter query as shown in the example below. The \`${name}\` rule accepts the following configuration options:
|
|
53
|
+
|
|
54
|
+
${Object.getOwnPropertyNames(linter_rules_1.LintingRules[name].defaultConfig).sort().map(key => `- ${(0, doc_types_1.shortLink)(`${configType}:::${key}`, types.info)}\\\n${(0, doc_types_1.getDocumentationForType)(`${configType}::${key}`, types.info)}`).join('\n')}
|
|
55
|
+
|
|
56
|
+
#### Example
|
|
57
|
+
|
|
58
|
+
${(0, doc_code_1.codeBlock)('r', example)}
|
|
59
|
+
|
|
60
|
+
The linting query can be used to run this rule on the above example:
|
|
61
|
+
|
|
62
|
+
${await (0, doc_query_1.showQuery)(shell, example, [{ type: 'linter', rules: [{ name, config: {} }] }], { collapseQuery: true })}
|
|
63
|
+
|
|
64
|
+
</details>
|
|
65
|
+
`.trim();
|
|
66
|
+
}
|
|
67
|
+
if (require.main === module) {
|
|
68
|
+
(0, log_1.setMinLevelOfAllLogs)(6 /* LogLevel.Fatal */);
|
|
69
|
+
const shell = new shell_1.RShell();
|
|
70
|
+
void getText(shell).then(str => {
|
|
71
|
+
console.log(str);
|
|
72
|
+
}).finally(() => {
|
|
73
|
+
shell.close();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=print-linter-wiki.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { LintingRuleConfig, LintingRuleNames } from './linter-rules';
|
|
2
|
+
import type { NormalizedAst } from '../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
3
|
+
import type { DataflowInformation } from '../dataflow/info';
|
|
4
|
+
import type { LintingResults } from './linter-format';
|
|
5
|
+
import type { DeepPartial } from 'ts-essentials';
|
|
6
|
+
export declare function executeLintingRule<Name extends LintingRuleNames>(ruleName: Name, input: {
|
|
7
|
+
normalize: NormalizedAst;
|
|
8
|
+
dataflow: DataflowInformation;
|
|
9
|
+
}, config?: DeepPartial<LintingRuleConfig<Name>>): LintingResults<Name>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeLintingRule = executeLintingRule;
|
|
4
|
+
const linter_rules_1 = require("./linter-rules");
|
|
5
|
+
const flowr_search_executor_1 = require("../search/flowr-search-executor");
|
|
6
|
+
const flowr_search_1 = require("../search/flowr-search");
|
|
7
|
+
function executeLintingRule(ruleName, input, config) {
|
|
8
|
+
const rule = linter_rules_1.LintingRules[ruleName];
|
|
9
|
+
const fullConfig = { ...rule.defaultConfig, ...config };
|
|
10
|
+
const ruleSearch = rule.createSearch(fullConfig, input);
|
|
11
|
+
const searchStart = Date.now();
|
|
12
|
+
const searchResult = (0, flowr_search_executor_1.runSearch)(ruleSearch, input);
|
|
13
|
+
const searchTime = Date.now() - searchStart;
|
|
14
|
+
const processStart = Date.now();
|
|
15
|
+
const result = rule.processSearchResult(new flowr_search_1.FlowrSearchElements(searchResult), fullConfig, input);
|
|
16
|
+
const processTime = Date.now() - processStart;
|
|
17
|
+
return {
|
|
18
|
+
...result,
|
|
19
|
+
'.meta': {
|
|
20
|
+
...result['.meta'],
|
|
21
|
+
searchTimeMs: searchTime,
|
|
22
|
+
processTimeMs: processTime
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=linter-executor.js.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { FlowrSearchLike } from '../search/flowr-search-builder';
|
|
2
|
+
import type { FlowrSearchElement, FlowrSearchElements } from '../search/flowr-search';
|
|
3
|
+
import type { MergeableRecord } from '../util/objects';
|
|
4
|
+
import type { GeneratorNames } from '../search/search-executor/search-generators';
|
|
5
|
+
import type { TransformerNames } from '../search/search-executor/search-transformer';
|
|
6
|
+
import type { NormalizedAst, ParentInformation } from '../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
7
|
+
import type { LintingRuleConfig, LintingRuleMetadata, LintingRuleNames, LintingRuleResult } from './linter-rules';
|
|
8
|
+
import type { DataflowInformation } from '../dataflow/info';
|
|
9
|
+
import type { DeepPartial } from 'ts-essentials';
|
|
10
|
+
/**
|
|
11
|
+
* The base interface for a linting rule, which contains all of its relevant settings.
|
|
12
|
+
* The registry of valid linting rules is stored in {@link LintingRules}.
|
|
13
|
+
*/
|
|
14
|
+
export interface LintingRule<Result extends LintingResult, Metadata extends MergeableRecord, Config extends MergeableRecord = never, Info = ParentInformation, Elements extends FlowrSearchElement<Info>[] = FlowrSearchElement<Info>[]> {
|
|
15
|
+
/**
|
|
16
|
+
* Creates a flowR search that will then be executed and whose results will be passed to {@link processSearchResult}.
|
|
17
|
+
* In the future, additional optimizations and transformations may be applied to the search between this function and {@link processSearchResult}.
|
|
18
|
+
*/
|
|
19
|
+
readonly createSearch: (config: Config, data: {
|
|
20
|
+
normalize: NormalizedAst;
|
|
21
|
+
dataflow: DataflowInformation;
|
|
22
|
+
}) => FlowrSearchLike<Info, GeneratorNames, TransformerNames[], FlowrSearchElements<Info, Elements>>;
|
|
23
|
+
/**
|
|
24
|
+
* Processes the search results of the search created through {@link createSearch}.
|
|
25
|
+
* This function is expected to return the linting results from this rule for the given search, ie usually the given script file.
|
|
26
|
+
*/
|
|
27
|
+
readonly processSearchResult: (elements: FlowrSearchElements<Info, Elements>, config: Config, data: {
|
|
28
|
+
normalize: NormalizedAst;
|
|
29
|
+
dataflow: DataflowInformation;
|
|
30
|
+
}) => {
|
|
31
|
+
results: Result[];
|
|
32
|
+
'.meta': Metadata;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* A function used to pretty-print the given linting result.
|
|
36
|
+
* By default, the {@link LintingResult#certainty} is automatically printed alongside this information.
|
|
37
|
+
*/
|
|
38
|
+
readonly prettyPrint: (result: Result, metadata: Metadata) => string;
|
|
39
|
+
/**
|
|
40
|
+
* The default config for this linting rule.
|
|
41
|
+
* The default config is combined with the user config when executing the rule.
|
|
42
|
+
*/
|
|
43
|
+
readonly defaultConfig: NoInfer<Config>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A linting result for a single linting rule match.
|
|
47
|
+
*/
|
|
48
|
+
export interface LintingResult {
|
|
49
|
+
readonly certainty: LintingCertainty;
|
|
50
|
+
}
|
|
51
|
+
export interface ConfiguredLintingRule<Name extends LintingRuleNames = LintingRuleNames> {
|
|
52
|
+
readonly name: Name;
|
|
53
|
+
readonly config: DeepPartial<LintingRuleConfig<Name>>;
|
|
54
|
+
}
|
|
55
|
+
export interface LintingResults<Name extends LintingRuleNames> {
|
|
56
|
+
results: LintingRuleResult<Name>[];
|
|
57
|
+
'.meta': LintingRuleMetadata<Name> & {
|
|
58
|
+
readonly searchTimeMs: number;
|
|
59
|
+
readonly processTimeMs: number;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export declare enum LintingCertainty {
|
|
63
|
+
Maybe = "maybe",
|
|
64
|
+
Definitely = "definitely"
|
|
65
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LintingCertainty = void 0;
|
|
4
|
+
var LintingCertainty;
|
|
5
|
+
(function (LintingCertainty) {
|
|
6
|
+
LintingCertainty["Maybe"] = "maybe";
|
|
7
|
+
LintingCertainty["Definitely"] = "definitely";
|
|
8
|
+
})(LintingCertainty || (exports.LintingCertainty = LintingCertainty = {}));
|
|
9
|
+
//# sourceMappingURL=linter-format.js.map
|