@eagleoutice/flowr 2.2.2 → 2.2.4
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 +412 -39
- package/benchmark/slicer.js +0 -1
- package/benchmark/summarizer/first-phase/process.js +18 -8
- package/benchmark/summarizer/summarizer.d.ts +1 -1
- package/benchmark/summarizer/summarizer.js +1 -1
- package/cli/benchmark-app.js +1 -1
- package/cli/common/script.js +0 -1
- package/cli/repl/commands/repl-cfg.js +38 -8
- package/cli/repl/commands/repl-commands.js +1 -1
- package/cli/repl/commands/repl-dataflow.js +45 -12
- package/cli/repl/commands/repl-normalize.js +38 -8
- package/cli/repl/commands/repl-parse.js +43 -2
- package/cli/repl/commands/repl-query.js +2 -2
- package/cli/repl/core.js +17 -8
- package/cli/repl/print-version.d.ts +1 -0
- package/cli/repl/print-version.js +8 -2
- package/cli/repl/server/connection.js +27 -15
- package/cli/repl/server/messages/all-messages.js +17 -7
- package/cli/repl/server/messages/message-repl.js +17 -7
- package/cli/repl/server/messages/message-slice.js +17 -7
- package/cli/script-core/statistics-helper-core.js +0 -1
- package/core/pipeline-executor.d.ts +6 -0
- package/core/pipeline-executor.js +8 -0
- package/core/print/dataflow-printer.js +3 -0
- package/core/print/normalize-printer.js +0 -1
- package/core/steps/all/core/01-parse-tree-sitter.d.ts +7 -0
- package/core/steps/pipeline/default-pipelines.d.ts +57 -47
- package/core/steps/pipeline/default-pipelines.js +23 -2
- package/core/steps/pipeline/pipeline.d.ts +1 -1
- package/core/steps/pipeline/pipeline.js +1 -1
- package/core/steps/pipeline-step.d.ts +1 -3
- package/dataflow/environments/resolve-by-name.d.ts +5 -2
- package/dataflow/environments/resolve-by-name.js +6 -4
- package/dataflow/extractor.d.ts +10 -0
- package/dataflow/extractor.js +10 -0
- package/dataflow/graph/resolve-graph.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +20 -4
- package/documentation/data/server/doc-data-server-messages.js +1 -2
- package/documentation/doc-util/doc-auto-gen.d.ts +1 -0
- package/documentation/doc-util/doc-auto-gen.js +5 -1
- package/documentation/doc-util/doc-benchmarks.d.ts +23 -0
- package/documentation/doc-util/doc-benchmarks.js +76 -0
- package/documentation/doc-util/doc-code.d.ts +1 -0
- package/documentation/doc-util/doc-code.js +4 -0
- package/documentation/doc-util/doc-dfg.d.ts +5 -3
- package/documentation/doc-util/doc-dfg.js +10 -8
- package/documentation/doc-util/doc-files.d.ts +2 -1
- package/documentation/doc-util/doc-files.js +3 -2
- package/documentation/doc-util/doc-normalized-ast.d.ts +2 -1
- package/documentation/doc-util/doc-normalized-ast.js +4 -5
- package/documentation/doc-util/doc-repl.d.ts +6 -2
- package/documentation/doc-util/doc-repl.js +10 -6
- package/documentation/doc-util/doc-server-message.js +1 -1
- package/documentation/doc-util/doc-structure.d.ts +1 -1
- package/documentation/doc-util/doc-structure.js +2 -2
- package/documentation/doc-util/doc-types.d.ts +8 -5
- package/documentation/doc-util/doc-types.js +31 -18
- package/documentation/index.d.ts +9 -0
- package/documentation/index.js +26 -0
- package/documentation/print-capabilities-markdown.js +105 -19
- package/documentation/print-core-wiki.d.ts +1 -0
- package/documentation/print-core-wiki.js +413 -0
- package/documentation/print-dataflow-graph-wiki.js +27 -27
- package/documentation/print-interface-wiki.js +22 -16
- package/documentation/print-linting-and-testing-wiki.js +29 -9
- package/documentation/print-normalized-ast-wiki.js +22 -17
- package/documentation/print-query-wiki.js +7 -7
- package/documentation/print-readme.d.ts +1 -0
- package/documentation/print-readme.js +160 -0
- package/documentation/print-search-wiki.js +2 -1
- package/package.json +30 -41
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +77 -45
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +3 -0
- package/queries/catalog/dependencies-query/dependencies-query-format.js +3 -2
- package/queries/catalog/happens-before-query/happens-before-query-format.js +1 -1
- package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +1 -1
- package/queries/catalog/resolve-value-query/resolve-value-query-format.js +1 -1
- package/queries/catalog/search-query/search-query-format.js +1 -1
- package/r-bridge/data/data.d.ts +48 -7
- package/r-bridge/data/data.js +62 -8
- package/r-bridge/data/types.d.ts +7 -1
- package/r-bridge/lang-4.x/ast/model/model.d.ts +2 -3
- package/r-bridge/lang-4.x/ast/model/processing/decorate.d.ts +2 -0
- package/r-bridge/lang-4.x/ast/model/processing/node-id.js +2 -5
- package/r-bridge/lang-4.x/ast/parser/json/format.d.ts +6 -0
- package/r-bridge/lang-4.x/ast/parser/json/format.js +6 -0
- package/r-bridge/lang-4.x/ast/parser/json/parser.d.ts +13 -2
- package/r-bridge/lang-4.x/ast/parser/json/parser.js +19 -3
- package/r-bridge/lang-4.x/ast/parser/main/internal/structure/normalize-root.d.ts +3 -0
- package/r-bridge/lang-4.x/ast/parser/main/internal/structure/normalize-root.js +3 -0
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.d.ts +1 -0
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.js +3 -0
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +6 -1
- package/r-bridge/parser.d.ts +10 -0
- package/r-bridge/parser.js +26 -2
- package/r-bridge/shell.js +18 -8
- package/search/flowr-search-builder.d.ts +1 -2
- package/search/flowr-search-builder.js +1 -3
- package/statistics/features/supported/comments/comments.js +17 -7
- package/statistics/features/supported/used-functions/post-process.js +0 -1
- package/statistics/features/supported/used-packages/used-packages.js +17 -7
- package/statistics/features/supported/values/values.js +17 -7
- package/statistics/summarizer/summarizer.js +1 -2
- package/util/files.js +17 -7
- package/util/json.js +0 -2
- package/util/mermaid/dfg.d.ts +3 -0
- package/util/mermaid/dfg.js +24 -8
- package/util/numbers.d.ts +1 -0
- package/util/numbers.js +5 -0
- package/util/parallel.js +17 -7
- package/util/quads.js +3 -3
- package/util/strings.d.ts +9 -0
- package/util/strings.js +14 -0
- package/util/version.js +1 -1
|
@@ -13,13 +13,15 @@ const resolve_graph_1 = require("../../dataflow/graph/resolve-graph");
|
|
|
13
13
|
const diff_1 = require("../../dataflow/graph/diff");
|
|
14
14
|
const assert_1 = require("../../util/assert");
|
|
15
15
|
const time_1 = require("../../util/time");
|
|
16
|
-
|
|
16
|
+
const doc_files_1 = require("./doc-files");
|
|
17
|
+
function printDfGraph(graph, mark, simplified = false) {
|
|
17
18
|
return `
|
|
18
19
|
\`\`\`mermaid
|
|
19
20
|
${(0, dfg_1.graphToMermaid)({
|
|
20
21
|
graph,
|
|
21
22
|
prefix: 'flowchart LR',
|
|
22
|
-
mark
|
|
23
|
+
mark,
|
|
24
|
+
simplified
|
|
23
25
|
}).string}
|
|
24
26
|
\`\`\`
|
|
25
27
|
`;
|
|
@@ -32,18 +34,18 @@ function formatSideEffect(ef) {
|
|
|
32
34
|
return `${ef}`;
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
|
-
async function printDfGraphForCode(
|
|
37
|
+
async function printDfGraphForCode(parser, code, { simplified = false, mark, showCode = true, codeOpen = false, exposeResult, switchCodeAndGraph = false } = {}) {
|
|
36
38
|
const now = performance.now();
|
|
37
|
-
const result = await
|
|
38
|
-
parser: shell,
|
|
39
|
+
const result = await (0, default_pipelines_1.createDataflowPipeline)(parser, {
|
|
39
40
|
request: (0, retriever_1.requestFromInput)(code)
|
|
40
41
|
}).allRemainingSteps();
|
|
41
42
|
const duration = performance.now() - now;
|
|
42
43
|
if (switchCodeAndGraph) {
|
|
43
44
|
(0, assert_1.guard)(showCode, 'can not switch code and graph if code is not shown');
|
|
44
45
|
}
|
|
45
|
-
const metaInfo = `The analysis required _${(0, time_1.printAsMs)(duration)}_ (including parse and normalize) within the generation environment.`;
|
|
46
|
-
const dfGraph = printDfGraph(result.dataflow.graph, mark);
|
|
46
|
+
const metaInfo = `The analysis required _${(0, time_1.printAsMs)(duration)}_ (including parse and normalize, using the [${parser.name}](${doc_files_1.FlowrWikiBaseRef}/Engines) engine) within the generation environment.`;
|
|
47
|
+
const dfGraph = printDfGraph(result.dataflow.graph, mark, simplified);
|
|
48
|
+
const simplyText = simplified ? '(simplified) ' : '';
|
|
47
49
|
let resultText = '\n\n';
|
|
48
50
|
if (showCode) {
|
|
49
51
|
const codeText = `\`\`\`r
|
|
@@ -53,7 +55,7 @@ ${code}
|
|
|
53
55
|
resultText += `
|
|
54
56
|
<details${codeOpen ? ' open' : ''}>
|
|
55
57
|
|
|
56
|
-
<summary style="color:gray">${switchCodeAndGraph ?
|
|
58
|
+
<summary style="color:gray">${switchCodeAndGraph ? `${simplyText}Dataflow Graph of the R Code` : `R Code of the ${simplyText}Dataflow Graph`}</summary>
|
|
57
59
|
|
|
58
60
|
${metaInfo} ${mark ? `The following marks are used in the graph to highlight sub-parts (uses ids): {${[...mark].join(', ')}}.` : ''}
|
|
59
61
|
We encountered ${result.dataflow.graph.unknownSideEffects.size > 0 ? 'unknown side effects (with ids: ' + [...result.dataflow.graph.unknownSideEffects].map(formatSideEffect).join(', ') + ')' : 'no unknown side effects'} during the analysis.
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export declare const FlowrGithubBaseRef = "https://github.com/flowr-analysis";
|
|
2
2
|
export declare const FlowrSiteBaseRef = "https://flowr-analysis.github.io/flowr";
|
|
3
3
|
export declare const RemoteFlowrFilePathBaseRef = "https://github.com/flowr-analysis/flowr/tree/main/";
|
|
4
|
-
export declare const FlowrWikiBaseRef = "https://github.com/flowr-analysis/flowr/wiki
|
|
4
|
+
export declare const FlowrWikiBaseRef = "https://github.com/flowr-analysis/flowr/wiki";
|
|
5
5
|
export declare const FlowrNpmRef = "https://www.npmjs.com/package/@eagleoutice/flowr";
|
|
6
6
|
export declare const FlowrDockerRef = "https://hub.docker.com/r/eagleoutice/flowr";
|
|
7
7
|
export declare const FlowrCodecovRef = "https://app.codecov.io/gh/flowr-analysis/flowr";
|
|
8
|
+
export declare const FlowrVsCode = "https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr";
|
|
8
9
|
export declare function getFilePathMd(path: string): string;
|
|
9
10
|
export declare function getFileContentFromRoot(path: string): string;
|
|
10
11
|
export declare function linkFlowRSourceFile(path: string): string;
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.FlowrCodecovRef = exports.FlowrDockerRef = exports.FlowrNpmRef = exports.FlowrWikiBaseRef = exports.RemoteFlowrFilePathBaseRef = exports.FlowrSiteBaseRef = exports.FlowrGithubBaseRef = void 0;
|
|
6
|
+
exports.FlowrVsCode = exports.FlowrCodecovRef = exports.FlowrDockerRef = exports.FlowrNpmRef = exports.FlowrWikiBaseRef = exports.RemoteFlowrFilePathBaseRef = exports.FlowrSiteBaseRef = exports.FlowrGithubBaseRef = void 0;
|
|
7
7
|
exports.getFilePathMd = getFilePathMd;
|
|
8
8
|
exports.getFileContentFromRoot = getFileContentFromRoot;
|
|
9
9
|
exports.linkFlowRSourceFile = linkFlowRSourceFile;
|
|
@@ -11,10 +11,11 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
11
11
|
exports.FlowrGithubBaseRef = 'https://github.com/flowr-analysis';
|
|
12
12
|
exports.FlowrSiteBaseRef = 'https://flowr-analysis.github.io/flowr';
|
|
13
13
|
exports.RemoteFlowrFilePathBaseRef = `${exports.FlowrGithubBaseRef}/flowr/tree/main/`;
|
|
14
|
-
exports.FlowrWikiBaseRef = `${exports.FlowrGithubBaseRef}/flowr/wiki
|
|
14
|
+
exports.FlowrWikiBaseRef = `${exports.FlowrGithubBaseRef}/flowr/wiki`;
|
|
15
15
|
exports.FlowrNpmRef = 'https://www.npmjs.com/package/@eagleoutice/flowr';
|
|
16
16
|
exports.FlowrDockerRef = 'https://hub.docker.com/r/eagleoutice/flowr';
|
|
17
17
|
exports.FlowrCodecovRef = 'https://app.codecov.io/gh/flowr-analysis/flowr';
|
|
18
|
+
exports.FlowrVsCode = 'https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr';
|
|
18
19
|
function getFilePathMd(path) {
|
|
19
20
|
// we go one up as we are in doc-util now :D #convenience
|
|
20
21
|
const fullpath = require.resolve('../' + path);
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { DataflowGraph } from '../../dataflow/graph/graph';
|
|
2
2
|
import type { RShell } from '../../r-bridge/shell';
|
|
3
3
|
import type { RNodeWithParent } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
+
import type { KnownParser } from '../../r-bridge/parser';
|
|
4
5
|
export declare function printNormalizedAst(ast: RNodeWithParent, prefix?: string): string;
|
|
5
6
|
export interface PrintNormalizedAstOptions {
|
|
6
7
|
readonly showCode?: boolean;
|
|
7
8
|
readonly prefix?: string;
|
|
8
9
|
}
|
|
9
|
-
export declare function printNormalizedAstForCode(
|
|
10
|
+
export declare function printNormalizedAstForCode(parser: KnownParser, code: string, { showCode, prefix }?: PrintNormalizedAstOptions): Promise<string>;
|
|
10
11
|
/** returns resolved expected df graph */
|
|
11
12
|
export declare function verifyExpectedSubgraph(shell: RShell, code: string, expectedSubgraph: DataflowGraph): Promise<DataflowGraph>;
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.printNormalizedAst = printNormalizedAst;
|
|
4
4
|
exports.printNormalizedAstForCode = printNormalizedAstForCode;
|
|
5
5
|
exports.verifyExpectedSubgraph = verifyExpectedSubgraph;
|
|
6
|
-
const pipeline_executor_1 = require("../../core/pipeline-executor");
|
|
7
6
|
const default_pipelines_1 = require("../../core/steps/pipeline/default-pipelines");
|
|
8
7
|
const retriever_1 = require("../../r-bridge/retriever");
|
|
9
8
|
const decorate_1 = require("../../r-bridge/lang-4.x/ast/model/processing/decorate");
|
|
@@ -12,6 +11,7 @@ const diff_1 = require("../../dataflow/graph/diff");
|
|
|
12
11
|
const assert_1 = require("../../util/assert");
|
|
13
12
|
const ast_1 = require("../../util/mermaid/ast");
|
|
14
13
|
const time_1 = require("../../util/time");
|
|
14
|
+
const doc_files_1 = require("./doc-files");
|
|
15
15
|
function printNormalizedAst(ast, prefix = 'flowchart TD\n') {
|
|
16
16
|
return `
|
|
17
17
|
\`\`\`mermaid
|
|
@@ -19,14 +19,13 @@ ${(0, ast_1.normalizedAstToMermaid)(ast, prefix)}
|
|
|
19
19
|
\`\`\`
|
|
20
20
|
`;
|
|
21
21
|
}
|
|
22
|
-
async function printNormalizedAstForCode(
|
|
22
|
+
async function printNormalizedAstForCode(parser, code, { showCode = true, prefix = 'flowchart TD\n' } = {}) {
|
|
23
23
|
const now = performance.now();
|
|
24
|
-
const result = await
|
|
25
|
-
parser: shell,
|
|
24
|
+
const result = await (0, default_pipelines_1.createNormalizePipeline)(parser, {
|
|
26
25
|
request: (0, retriever_1.requestFromInput)(code)
|
|
27
26
|
}).allRemainingSteps();
|
|
28
27
|
const duration = performance.now() - now;
|
|
29
|
-
const metaInfo = `The analysis required _${(0, time_1.printAsMs)(duration)}_ (including parsing with the
|
|
28
|
+
const metaInfo = `The analysis required _${(0, time_1.printAsMs)(duration)}_ (including parsing with the [${parser.name}](${doc_files_1.FlowrWikiBaseRef}/Engines) engine) within the generation environment.`;
|
|
30
29
|
return '\n\n' + printNormalizedAst(result.normalize.ast, prefix) + (showCode ? `
|
|
31
30
|
<details>
|
|
32
31
|
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { KnownParser } from '../../r-bridge/parser';
|
|
2
2
|
export declare function printReplHelpAsMarkdownTable(): string;
|
|
3
3
|
export interface DocumentReplSessionOptions {
|
|
4
4
|
/** defaults to false and shows starting the repl */
|
|
5
5
|
hideEntry?: boolean;
|
|
6
6
|
/** defaults to false and allows access to the R session */
|
|
7
7
|
allowRSessionAccess?: boolean;
|
|
8
|
+
/** defaults to false and opens the details section by default */
|
|
9
|
+
openOutput?: boolean;
|
|
10
|
+
/** additional arguments to pass to the repl */
|
|
11
|
+
args?: string;
|
|
8
12
|
}
|
|
9
13
|
export interface DocumentReplCommand {
|
|
10
14
|
command: string;
|
|
11
15
|
description: string;
|
|
12
16
|
}
|
|
13
|
-
export declare function documentReplSession(
|
|
17
|
+
export declare function documentReplSession(parser: KnownParser, commands: readonly DocumentReplCommand[], options?: DocumentReplSessionOptions): Promise<string>;
|
|
@@ -10,6 +10,7 @@ const ansi_1 = require("../../util/ansi");
|
|
|
10
10
|
const doc_docker_1 = require("./doc-docker");
|
|
11
11
|
const prompt_1 = require("../../cli/repl/prompt");
|
|
12
12
|
const doc_code_1 = require("./doc-code");
|
|
13
|
+
const print_version_1 = require("../../cli/repl/print-version");
|
|
13
14
|
function printHelpForScript(script, starredVersion) {
|
|
14
15
|
let base = `| **${(0, doc_cli_option_1.getReplCommand)(script[0], false, starredVersion !== undefined)}** | ${script[1].description}`;
|
|
15
16
|
if (starredVersion) {
|
|
@@ -37,7 +38,7 @@ function printReplHelpAsMarkdownTable() {
|
|
|
37
38
|
${scriptHelp.sort().join('\n')}
|
|
38
39
|
`;
|
|
39
40
|
}
|
|
40
|
-
async function documentReplSession(
|
|
41
|
+
async function documentReplSession(parser, commands, options) {
|
|
41
42
|
const collect = [];
|
|
42
43
|
for (const command of commands) {
|
|
43
44
|
const entry = { command, lines: [] };
|
|
@@ -50,11 +51,14 @@ async function documentReplSession(shell, commands, options) {
|
|
|
50
51
|
entry.lines.push(msg);
|
|
51
52
|
}
|
|
52
53
|
};
|
|
53
|
-
await (0, core_1.replProcessAnswer)(collectingOutput, command.command,
|
|
54
|
+
await (0, core_1.replProcessAnswer)(collectingOutput, command.command, parser, options?.allowRSessionAccess ?? false);
|
|
54
55
|
collect.push(entry);
|
|
55
56
|
}
|
|
56
57
|
let result = '';
|
|
57
|
-
let cache = options?.hideEntry ? '' :
|
|
58
|
+
let cache = options?.hideEntry ? '' : `$ docker run -it --rm ${doc_docker_1.DockerName} ${options?.args ? options?.args + ' ' : ''}# or npm run flowr ${options?.args ? '-- ' + options?.args : ''}\n`;
|
|
59
|
+
if (!options?.hideEntry) {
|
|
60
|
+
cache += await (0, print_version_1.versionReplString)(parser) + '\n';
|
|
61
|
+
}
|
|
58
62
|
for (const { command, lines } of collect) {
|
|
59
63
|
if (lines.length === 0) {
|
|
60
64
|
cache += prompt_1.rawPrompt + ' ' + command.command + '\n';
|
|
@@ -62,13 +66,13 @@ async function documentReplSession(shell, commands, options) {
|
|
|
62
66
|
}
|
|
63
67
|
result += `
|
|
64
68
|
${(0, doc_code_1.codeBlock)('shell', cache + prompt_1.rawPrompt + ' ' + command.command)}
|
|
65
|
-
<details>
|
|
69
|
+
<details${options?.openOutput ? ' open' : ''}>
|
|
66
70
|
<summary style='color:gray'>Output</summary>
|
|
67
71
|
|
|
68
|
-
${command.description}
|
|
69
|
-
|
|
70
72
|
${(0, doc_code_1.codeBlock)('text', lines.join('\n'))}
|
|
71
73
|
|
|
74
|
+
${command.description}
|
|
75
|
+
|
|
72
76
|
</details>
|
|
73
77
|
|
|
74
78
|
`;
|
|
@@ -80,7 +80,7 @@ async function documentServerMessageResponse({ shell, title, messageType, messag
|
|
|
80
80
|
try {
|
|
81
81
|
await socket.waitForMessage(metaMessage.expectedType, 20);
|
|
82
82
|
}
|
|
83
|
-
catch
|
|
83
|
+
catch {
|
|
84
84
|
console.error('Failed to receive message', metaMessage.expectedType, 'has', socket.getMessages());
|
|
85
85
|
}
|
|
86
86
|
}
|
|
@@ -6,7 +6,7 @@ export interface DetailsOptions {
|
|
|
6
6
|
}
|
|
7
7
|
export declare function details(title: string, content: string, { color, open, hideIfEmpty, prefixInit }?: DetailsOptions): string;
|
|
8
8
|
export interface BlockOptions {
|
|
9
|
-
readonly type: 'NOTE' | 'WARNING' | '
|
|
9
|
+
readonly type: 'NOTE' | 'WARNING' | 'TIP' | 'IMPORTANT';
|
|
10
10
|
readonly content: string;
|
|
11
11
|
}
|
|
12
12
|
export declare function block({ type, content }: BlockOptions): string;
|
|
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.details = details;
|
|
4
4
|
exports.block = block;
|
|
5
5
|
const doc_general_1 = require("./doc-general");
|
|
6
|
-
function details(title, content, { color
|
|
6
|
+
function details(title, content, { color, open = false, hideIfEmpty = true, prefixInit = '' } = {}) {
|
|
7
7
|
return hideIfEmpty && content.trim().length === 0 ? '' : `
|
|
8
|
-
${prefixInit}<details${open ? ' open' : ''}><summary style="
|
|
8
|
+
${prefixInit}<details${open ? ' open' : ''}><summary style="${color ? 'color:' + color : ''}">${title}</summary>
|
|
9
9
|
|
|
10
10
|
${content}
|
|
11
11
|
|
|
@@ -25,22 +25,25 @@ export interface MermaidTypeReport {
|
|
|
25
25
|
program: ts.Program;
|
|
26
26
|
}
|
|
27
27
|
export declare function getTypesFromFolderAsMermaid(options: GetTypesAsMermaidOption): MermaidTypeReport;
|
|
28
|
-
export declare function implSnippet(node: TypeElementInSource | undefined, program: ts.Program, showName?: boolean, nesting?: number): string;
|
|
28
|
+
export declare function implSnippet(node: TypeElementInSource | undefined, program: ts.Program, showName?: boolean, nesting?: number, open?: boolean): string;
|
|
29
29
|
export interface PrintHierarchyArguments {
|
|
30
30
|
readonly program: ts.Program;
|
|
31
|
-
readonly
|
|
31
|
+
readonly info: TypeElementInSource[];
|
|
32
32
|
readonly root: string;
|
|
33
33
|
readonly collapseFromNesting?: number;
|
|
34
34
|
readonly initialNesting?: number;
|
|
35
35
|
readonly maxDepth?: number;
|
|
36
|
+
readonly openTop?: boolean;
|
|
36
37
|
}
|
|
37
38
|
export declare const mermaidHide: string[];
|
|
38
|
-
export declare function printHierarchy({ program,
|
|
39
|
+
export declare function printHierarchy({ program, info, root, collapseFromNesting, initialNesting, maxDepth, openTop }: PrintHierarchyArguments): string;
|
|
39
40
|
/**
|
|
40
41
|
* Create a short link to a type in the documentation
|
|
41
|
-
* @param name - The name of the type, e.g. `MyType`, may include a container, e.g
|
|
42
|
+
* @param name - The name of the type, e.g. `MyType`, may include a container, e.g.,`MyContainer::MyType` (this works with function nestings too)
|
|
43
|
+
* Use `:::` if you want to access a scoped function, but the name should be displayed without the scope
|
|
42
44
|
* @param hierarchy - The hierarchy of types to search in
|
|
43
45
|
* @param codeStyle - Whether to use code style for the link
|
|
46
|
+
* @param realNameWrapper - How to highlight the function in name in the `x::y` format?
|
|
44
47
|
*/
|
|
45
|
-
export declare function shortLink(name: string, hierarchy: TypeElementInSource[], codeStyle?: boolean): string;
|
|
48
|
+
export declare function shortLink(name: string, hierarchy: readonly TypeElementInSource[], codeStyle?: boolean, realNameWrapper?: string): string;
|
|
46
49
|
export declare function getDocumentationForType(name: string, hierarchy: TypeElementInSource[]): string;
|
|
@@ -218,7 +218,7 @@ function collectHierarchyInformation(sourceFiles, options) {
|
|
|
218
218
|
return hierarchyList;
|
|
219
219
|
}
|
|
220
220
|
function getTypePathLink({ filePath, lineNumber }, prefix = doc_files_1.RemoteFlowrFilePathBaseRef) {
|
|
221
|
-
const fromSource = filePath.replace(/^.*\/src\//, 'src/');
|
|
221
|
+
const fromSource = filePath.replace(/^.*\/src\//, 'src/').replace(/^.*\/test\//, 'test/');
|
|
222
222
|
return `${prefix}/${fromSource}#L${lineNumber}`;
|
|
223
223
|
}
|
|
224
224
|
function generateMermaidClassDiagram(hierarchyList, rootName, options, visited = new Set()) {
|
|
@@ -305,33 +305,36 @@ function getTypesFromFolderAsMermaid(options) {
|
|
|
305
305
|
}
|
|
306
306
|
return getTypesFromFileAsMermaid(files, options);
|
|
307
307
|
}
|
|
308
|
-
function implSnippet(node, program, showName = true, nesting = 0) {
|
|
308
|
+
function implSnippet(node, program, showName = true, nesting = 0, open = false) {
|
|
309
309
|
(0, assert_1.guard)(node !== undefined, 'Node must be defined => invalid change of type name?');
|
|
310
310
|
const indent = ' '.repeat(nesting * 2);
|
|
311
311
|
const bold = node.kind === 'interface' || node.kind === 'enum' ? '**' : '';
|
|
312
312
|
const sep = node.comments ? ' \n' : '\n';
|
|
313
313
|
let text = node.comments?.join('\n') ?? '';
|
|
314
|
+
if (text.trim() !== '') {
|
|
315
|
+
text = ' ' + text;
|
|
316
|
+
}
|
|
314
317
|
const code = node.node.getFullText(program.getSourceFile(node.node.getSourceFile().fileName));
|
|
315
|
-
text += `\n${
|
|
318
|
+
text += `\n<details${open ? ' open' : ''}><summary style="color:gray">Defined at <a href="${getTypePathLink(node)}">${getTypePathLink(node, '.')}</a></summary>\n\n${(0, doc_code_1.codeBlock)('ts', code)}\n\n</details>\n`;
|
|
316
319
|
const init = showName ? `* ${bold}[${node.name}](${getTypePathLink(node)})${bold} ${sep}${indent}` : '';
|
|
317
320
|
return ` ${indent}${showName ? init : ''} ${text.replaceAll('\t', ' ').split(/\n/g).join(`\n${indent} `)}`;
|
|
318
321
|
}
|
|
319
322
|
exports.mermaidHide = ['Leaf', 'Location', 'Namespace', 'Base', 'WithChildren', 'Partial', 'RAccessBase'];
|
|
320
|
-
function printHierarchy({ program,
|
|
323
|
+
function printHierarchy({ program, info, root, collapseFromNesting = 1, initialNesting = 0, maxDepth = 20, openTop }) {
|
|
321
324
|
if (initialNesting > maxDepth) {
|
|
322
325
|
return '';
|
|
323
326
|
}
|
|
324
|
-
const node =
|
|
327
|
+
const node = info.find(e => e.name === root);
|
|
325
328
|
if (!node) {
|
|
326
329
|
return '';
|
|
327
330
|
}
|
|
328
|
-
const thisLine = implSnippet(node, program, true, initialNesting);
|
|
331
|
+
const thisLine = implSnippet(node, program, true, initialNesting, initialNesting === 0 && openTop);
|
|
329
332
|
const result = [];
|
|
330
333
|
for (const baseType of node.extends) {
|
|
331
334
|
if (exports.mermaidHide.includes(baseType)) {
|
|
332
335
|
continue;
|
|
333
336
|
}
|
|
334
|
-
const res = printHierarchy({ program,
|
|
337
|
+
const res = printHierarchy({ program, info: info, root: baseType, collapseFromNesting, initialNesting: initialNesting + 1, maxDepth });
|
|
335
338
|
result.push(res);
|
|
336
339
|
}
|
|
337
340
|
const out = result.join('\n');
|
|
@@ -345,32 +348,42 @@ function printHierarchy({ program, hierarchy, root, collapseFromNesting = 1, ini
|
|
|
345
348
|
function retrieveNode(name, hierarchy) {
|
|
346
349
|
let container = undefined;
|
|
347
350
|
if (name.includes('::')) {
|
|
348
|
-
[container, name] = name.split(
|
|
351
|
+
[container, name] = name.split(/:::?/);
|
|
349
352
|
}
|
|
350
|
-
|
|
351
|
-
if (
|
|
353
|
+
let node = hierarchy.filter(e => e.name === name);
|
|
354
|
+
if (node.length === 0) {
|
|
352
355
|
return undefined;
|
|
353
356
|
}
|
|
354
|
-
else if (container
|
|
355
|
-
|
|
357
|
+
else if (container) {
|
|
358
|
+
node = node.filter(n => n.extends.includes(container));
|
|
359
|
+
if (node.length === 0) {
|
|
360
|
+
return undefined;
|
|
361
|
+
}
|
|
356
362
|
}
|
|
357
|
-
return [container, name, node];
|
|
363
|
+
return [container, name, node[0]];
|
|
358
364
|
}
|
|
359
365
|
/**
|
|
360
366
|
* Create a short link to a type in the documentation
|
|
361
|
-
* @param name - The name of the type, e.g. `MyType`, may include a container, e.g
|
|
367
|
+
* @param name - The name of the type, e.g. `MyType`, may include a container, e.g.,`MyContainer::MyType` (this works with function nestings too)
|
|
368
|
+
* Use `:::` if you want to access a scoped function, but the name should be displayed without the scope
|
|
362
369
|
* @param hierarchy - The hierarchy of types to search in
|
|
363
370
|
* @param codeStyle - Whether to use code style for the link
|
|
371
|
+
* @param realNameWrapper - How to highlight the function in name in the `x::y` format?
|
|
364
372
|
*/
|
|
365
|
-
function shortLink(name, hierarchy, codeStyle = true) {
|
|
373
|
+
function shortLink(name, hierarchy, codeStyle = true, realNameWrapper = 'b') {
|
|
366
374
|
const res = retrieveNode(name, hierarchy);
|
|
367
375
|
if (!res) {
|
|
376
|
+
console.error(`Could not find node ${name} when resolving short link!`);
|
|
368
377
|
return '';
|
|
369
378
|
}
|
|
370
|
-
const [
|
|
371
|
-
|
|
379
|
+
const [, mainName, node] = res;
|
|
380
|
+
let pkg = res[0];
|
|
381
|
+
if (name.includes(':::')) {
|
|
382
|
+
pkg = undefined;
|
|
383
|
+
}
|
|
384
|
+
const comments = node.comments?.join('\n').replace(/\\?\n|```[a-zA-Z]*|\s\s*/g, ' ').replace(/<\/?code>|`/g, '').replace(/<\/?p\/?>/g, ' ').replace(/"/g, '\'') ?? '';
|
|
372
385
|
return `[${codeStyle ? '<code>' : ''}${(node.comments?.length ?? 0) > 0 ?
|
|
373
|
-
(0, html_hover_over_1.textWithTooltip)(pkg ? `${pkg}
|
|
386
|
+
(0, html_hover_over_1.textWithTooltip)(pkg ? `${pkg}::<${realNameWrapper}>${mainName}</${realNameWrapper}>` : mainName, comments.length > 400 ? comments.slice(0, 400) + '...' : comments) : node.name}${codeStyle ? '</code>' : ''}](${getTypePathLink(node)})`;
|
|
374
387
|
}
|
|
375
388
|
function getDocumentationForType(name, hierarchy) {
|
|
376
389
|
const res = retrieveNode(name, hierarchy);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './print-core-wiki';
|
|
2
|
+
export * from './print-query-wiki';
|
|
3
|
+
export * from './print-search-wiki';
|
|
4
|
+
export * from './print-engines-wiki';
|
|
5
|
+
export * from './print-interface-wiki';
|
|
6
|
+
export * from './print-dataflow-graph-wiki';
|
|
7
|
+
export * from './print-normalized-ast-wiki';
|
|
8
|
+
export * from './print-capabilities-markdown';
|
|
9
|
+
export * from './print-linting-and-testing-wiki';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./print-core-wiki"), exports);
|
|
18
|
+
__exportStar(require("./print-query-wiki"), exports);
|
|
19
|
+
__exportStar(require("./print-search-wiki"), exports);
|
|
20
|
+
__exportStar(require("./print-engines-wiki"), exports);
|
|
21
|
+
__exportStar(require("./print-interface-wiki"), exports);
|
|
22
|
+
__exportStar(require("./print-dataflow-graph-wiki"), exports);
|
|
23
|
+
__exportStar(require("./print-normalized-ast-wiki"), exports);
|
|
24
|
+
__exportStar(require("./print-capabilities-markdown"), exports);
|
|
25
|
+
__exportStar(require("./print-linting-and-testing-wiki"), exports);
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1,18 +1,81 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
const data_1 = require("../r-bridge/data/data");
|
|
4
|
-
const version_1 = require("../util/version");
|
|
5
7
|
const log_1 = require("../../test/functionality/_helper/log");
|
|
8
|
+
const doc_auto_gen_1 = require("./doc-util/doc-auto-gen");
|
|
9
|
+
const strings_1 = require("../util/strings");
|
|
10
|
+
const doc_general_1 = require("./doc-util/doc-general");
|
|
11
|
+
const tree_sitter_executor_1 = require("../r-bridge/lang-4.x/tree-sitter/tree-sitter-executor");
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const doc_structure_1 = require("./doc-util/doc-structure");
|
|
14
|
+
const detailedInfoFile = 'coverage/flowr-test-details.json';
|
|
15
|
+
function obtainDetailedInfos() {
|
|
16
|
+
if (!fs_1.default.existsSync(detailedInfoFile)) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const content = fs_1.default.readFileSync(detailedInfoFile).toString();
|
|
20
|
+
const base = JSON.parse(content);
|
|
21
|
+
const out = new Map();
|
|
22
|
+
for (const [key, values] of base) {
|
|
23
|
+
out.set(key, values.map(v => ({
|
|
24
|
+
id: v.id,
|
|
25
|
+
name: v.name,
|
|
26
|
+
capabilities: new Set(v.capabilities),
|
|
27
|
+
context: new Set(v.context)
|
|
28
|
+
})));
|
|
29
|
+
}
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
6
32
|
const supportedSymbolMap = new Map([
|
|
7
|
-
['not', '
|
|
8
|
-
['partially', '
|
|
9
|
-
['fully', '
|
|
33
|
+
['not', '🔴'],
|
|
34
|
+
['partially', '🔶'],
|
|
35
|
+
['fully', '🟩']
|
|
10
36
|
]);
|
|
11
|
-
function
|
|
37
|
+
function getTestDetails(info, capability) {
|
|
38
|
+
if (!info.info) {
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
const totalTests = info.info.get(capability.id);
|
|
42
|
+
const uniqueTests = totalTests?.filter((v, i, a) => a.findIndex(t => t.id === v.id) === i);
|
|
43
|
+
if (!uniqueTests || uniqueTests.length === 0) {
|
|
44
|
+
return '';
|
|
45
|
+
}
|
|
46
|
+
const grouped = new Map();
|
|
47
|
+
for (const { context } of uniqueTests) {
|
|
48
|
+
for (const c of context) {
|
|
49
|
+
grouped.set(c, (grouped.get(c) ?? 0) + 1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (grouped.get('desugar-tree-sitter') !== undefined && grouped.get('desugar-tree-sitter') === grouped.get('desugar-shell')) {
|
|
53
|
+
grouped.set('desugar', grouped.get('desugar-tree-sitter') ?? 0);
|
|
54
|
+
grouped.delete('desugar-shell');
|
|
55
|
+
grouped.delete('desugar-tree-sitter');
|
|
56
|
+
}
|
|
57
|
+
grouped.delete('other'); // opinionated view on the categories
|
|
58
|
+
const output = grouped.get('output');
|
|
59
|
+
grouped.delete('output');
|
|
60
|
+
const testString = [`${uniqueTests.length} test${uniqueTests.length !== 1 ? 's' : ''}`];
|
|
61
|
+
// sort by count
|
|
62
|
+
const sorted = [...grouped.entries()].sort((a, b) => b[1] - a[1]);
|
|
63
|
+
for (const [context, count] of sorted) {
|
|
64
|
+
testString.push(`${context}: ${count}`);
|
|
65
|
+
}
|
|
66
|
+
if (output) {
|
|
67
|
+
testString.push(`and backed with output: ${output}`);
|
|
68
|
+
}
|
|
69
|
+
return ` (${testString.join(', ')})`;
|
|
70
|
+
}
|
|
71
|
+
function escapeId(id) {
|
|
72
|
+
return id.replace(/[^a-zA-Z0-9]/g, '_');
|
|
73
|
+
}
|
|
74
|
+
async function printSingleCapability(info, depth, index, capability) {
|
|
12
75
|
const indent = ' '.repeat(depth);
|
|
13
76
|
const indexStr = index.toString().padStart(2, ' ');
|
|
14
77
|
const nextLineIndent = ' '.repeat(depth + indexStr.length);
|
|
15
|
-
const mainLine = `${indent}${indexStr}.
|
|
78
|
+
const mainLine = `${indent}${indexStr}. <a id='${capability.id}'></a>**${capability.name}** <a href="#${escapeId(capability.id)}">🔗</a>${getTestDetails(info, capability)}`;
|
|
16
79
|
let nextLine = '';
|
|
17
80
|
if (capability.supported) {
|
|
18
81
|
nextLine += `${supportedSymbolMap.get(capability.supported)} `;
|
|
@@ -20,43 +83,66 @@ function printSingleCapability(depth, index, capability) {
|
|
|
20
83
|
if (capability.description) {
|
|
21
84
|
nextLine += capability.description;
|
|
22
85
|
}
|
|
23
|
-
if (capability.
|
|
24
|
-
nextLine +=
|
|
86
|
+
if (capability.url) {
|
|
87
|
+
nextLine += '\\\nSee ' + (0, strings_1.joinWithLast)(capability.url.map(({ name, href }) => `[${name}](${href})`)) + ' for more info.';
|
|
88
|
+
}
|
|
89
|
+
nextLine += ' Internal ID: `' + capability.id + '`';
|
|
90
|
+
if (capability.example) {
|
|
91
|
+
nextLine += `\n${(0, doc_general_1.prefixLines)(typeof capability.example === 'string' ? capability.example : await capability.example(info.parser), nextLineIndent + '> ')}`;
|
|
25
92
|
}
|
|
26
93
|
return nextLine ? `${mainLine}\\\n${nextLineIndent}${nextLine}` : mainLine;
|
|
27
94
|
}
|
|
28
|
-
function printAsMarkdown(capabilities, depth = 0, lines = []) {
|
|
95
|
+
async function printAsMarkdown(info, capabilities, depth = 0, lines = []) {
|
|
29
96
|
for (let i = 0; i < capabilities.length; i++) {
|
|
30
97
|
const capability = capabilities[i];
|
|
31
|
-
const result = printSingleCapability(depth, i + 1, capability);
|
|
98
|
+
const result = await printSingleCapability(info, depth, i + 1, capability);
|
|
32
99
|
lines.push(result);
|
|
33
100
|
if (capability.capabilities) {
|
|
34
|
-
printAsMarkdown(capability.capabilities, depth + 1, lines);
|
|
101
|
+
await printAsMarkdown(info, capability.capabilities, depth + 1, lines);
|
|
35
102
|
}
|
|
36
103
|
}
|
|
37
104
|
return lines.join('\n');
|
|
38
105
|
}
|
|
39
106
|
function getPreamble() {
|
|
40
|
-
|
|
41
|
-
const shortenFilename = module.filename.replace(/^.*src\//, 'src/');
|
|
42
|
-
return `_This document was generated from '${shortenFilename}' on ${currentDateAndTime} summarizing flowR's current capabilities (v${(0, version_1.flowrVersion)().format()})._
|
|
107
|
+
return `${(0, doc_auto_gen_1.autoGenHeader)({ filename: module.filename, purpose: 'current capabilities' })}
|
|
43
108
|
|
|
44
|
-
|
|
109
|
+
Each capability has an id that can be used to link to it (use the link symbol to get a direct link to the capability).
|
|
110
|
+
The internal id is also mentioned in the capability description. This id can be used to reference the capability in a labeled test within flowR.
|
|
45
111
|
Besides, we use colored bullets like this:
|
|
46
112
|
|
|
47
113
|
| <!-- --> | <!-- --> |
|
|
48
114
|
| ---------------------- | ----------------------------------------------------- |
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
115
|
+
| ${supportedSymbolMap.get('fully')} | _flowR_ is capable of handling this feature _fully_ |
|
|
116
|
+
| ${supportedSymbolMap.get('partially')} | _flowR_ is capable of handling this feature _partially_ |
|
|
117
|
+
| ${supportedSymbolMap.get('not')} | _flowR_ is _not_ capable of handling this feature |
|
|
52
118
|
|
|
53
119
|
:cloud: This could be a feature diagram... :cloud:
|
|
54
120
|
|
|
121
|
+
${(0, doc_structure_1.block)({
|
|
122
|
+
type: 'NOTE',
|
|
123
|
+
content: `
|
|
124
|
+
The capabilities are a qualitative measure of the features that flowR can handle.
|
|
125
|
+
Statements like "flowR can fully handle 50/80 capabilities" are discouraged as the capabilities may have a vastly different granularity.
|
|
126
|
+
Please prefer using a statement like "flowR has only partial support for feature 'XY'" (or simply reference this document) within the flowR sources.
|
|
127
|
+
`
|
|
128
|
+
})}
|
|
55
129
|
`;
|
|
56
130
|
}
|
|
131
|
+
async function print(parser) {
|
|
132
|
+
/* check if the detailed test data is available */
|
|
133
|
+
if (!fs_1.default.existsSync(detailedInfoFile)) {
|
|
134
|
+
console.warn('\x1b[31mNo detailed test data available. Run the full tests (npm run test-full) to generate it.\x1b[m');
|
|
135
|
+
}
|
|
136
|
+
return getPreamble() + await printAsMarkdown({ parser, info: obtainDetailedInfos() }, data_1.flowrCapabilities.capabilities);
|
|
137
|
+
}
|
|
57
138
|
/** if we run this script, we want a Markdown representation of the capabilities */
|
|
58
139
|
if (require.main === module) {
|
|
59
140
|
(0, log_1.setMinLevelOfAllLogs)(6 /* LogLevel.Fatal */);
|
|
60
|
-
|
|
141
|
+
void tree_sitter_executor_1.TreeSitterExecutor.initTreeSitter().then(() => {
|
|
142
|
+
const parser = new tree_sitter_executor_1.TreeSitterExecutor();
|
|
143
|
+
void print(parser).then(str => {
|
|
144
|
+
console.log(str);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
61
147
|
}
|
|
62
148
|
//# sourceMappingURL=print-capabilities-markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|