Skip to content

Commit d9c7445

Browse files
committed
feat:
1 parent fccf681 commit d9c7445

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

packages/myst-cli/src/process/mdast.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import {
6767
transformFilterOutputStreams,
6868
transformLiftCodeBlocksInJupytext,
6969
transformMystXRefs,
70+
liftOutputs,
7071
} from '../transforms/index.js';
7172
import type { ImageExtensions } from '../utils/resolveExtension.js';
7273
import { logMessagesFromVFile } from '../utils/logging.js';
@@ -240,6 +241,9 @@ export async function transformMdast(
240241

241242
transformRenderInlineExpressions(mdast, vfile);
242243
await transformOutputsToCache(session, mdast, kind, { minifyMaxCharacters });
244+
liftOutputs(session, mdast, vfile, {
245+
parseMyst: (content: string) => parseMyst(session, content, file),
246+
});
243247
transformFilterOutputStreams(mdast, vfile, frontmatter.settings);
244248
transformCitations(session, file, mdast, fileCitationRenderer, references);
245249
await unified()

packages/myst-cli/src/transforms/outputs.ts

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@ import { selectAll } from 'unist-util-select';
1212
import type { VFile } from 'vfile';
1313
import type { IOutput, IStream } from '@jupyterlab/nbformat';
1414
import type { MinifiedContent, MinifiedOutput, MinifiedMimeOutput } from 'nbtx';
15-
import { ensureString, extFromMimeType, minifyCellOutput, walkOutputs } from 'nbtx';
15+
import {
16+
convertToIOutputs,
17+
ensureString,
18+
extFromMimeType,
19+
minifyCellOutput,
20+
walkOutputs,
21+
} from 'nbtx';
22+
import { TexParser } from 'tex-to-myst';
1623
import { castSession } from '../session/cache.js';
1724
import type { ISession } from '../session/types.js';
1825
import { resolveOutputPath } from './images.js';
@@ -25,6 +32,82 @@ function getWriteDestination(hash: string, contentType: string, writeFolder: str
2532
return join(writeFolder, getFilename(hash, contentType));
2633
}
2734

35+
const MARKDOWN_MIME_TYPE = 'text/markdown';
36+
const SUPPORTED_MARKDOWN_VARIANTS = ['Original', 'GFM', 'CommonMark', 'myst'];
37+
38+
/**
39+
* Extract the `variant` parameter from a Markdown MIME type
40+
*
41+
* @param mimeType MIME type of the form `text/markdown;FOO=BAR`
42+
*/
43+
function extractVariantParameter(mimeType: string): string | undefined {
44+
const [variant] = Array.from(mimeType.matchAll(/;([^;]+)=([^;]+)/g))
45+
.filter(([name]) => name === 'variant')
46+
.map((pair) => pair[1]);
47+
return variant;
48+
}
49+
50+
/*
51+
* Determine the Markdown variant from a given MIME-type
52+
*
53+
* If the MIME-type is not a supported Markdown MIME, return undefined
54+
*
55+
* @param mimeType - MIME type
56+
*/
57+
function determineMarkdownVariant(
58+
mimeType: string,
59+
): { variant?: string; mimeType: string } | undefined {
60+
if (!mimeType.startsWith(MARKDOWN_MIME_TYPE)) {
61+
return;
62+
}
63+
const variant = extractVariantParameter(mimeType);
64+
if (!variant) {
65+
return { mimeType };
66+
}
67+
if (SUPPORTED_MARKDOWN_VARIANTS.includes(variant)) {
68+
return { mimeType, variant };
69+
}
70+
71+
return;
72+
}
73+
74+
/**
75+
* Lift outputs that contribute to the global document state
76+
*/
77+
export function liftOutputs(
78+
session: ISession,
79+
mdast: GenericParent,
80+
vfile: VFile,
81+
opts: { parseMyst: (source: string) => GenericParent },
82+
) {
83+
const cache = castSession(session);
84+
selectAll('output', mdast).forEach((output) => {
85+
let children: GenericNode[] | undefined;
86+
walkOutputs([(output as any).jupyter_data], (obj: any) => {
87+
if (children) {
88+
return;
89+
}
90+
const { content_type, content, hash } = obj;
91+
const { mimeType: markdownMimeType } = determineMarkdownVariant(content_type) ?? {};
92+
// Markdown output
93+
if (markdownMimeType) {
94+
const [cacheContent] = cache.$outputs[hash] ?? [];
95+
const ast = opts.parseMyst(content ?? cacheContent);
96+
children = ast.children;
97+
}
98+
// LaTeX (including math) output
99+
else if (content_type === 'text/latex') {
100+
const [cacheContent] = cache.$outputs[hash] ?? [];
101+
const state = new TexParser(content ?? cacheContent, vfile);
102+
children = state.ast.children;
103+
}
104+
});
105+
if (children) {
106+
(output as any).children = children;
107+
}
108+
});
109+
}
110+
28111
/**
29112
* Traverse all output nodes, minify their content, and cache on the session
30113
*/

0 commit comments

Comments
 (0)