Path: blob/master/src/packages/jupyter/ipynb/parse.ts
1447 views
/*1This is a very lightweight ipynb parser in pure javascript.23It's used, e.g., in our analogue of nbviewer.4*/56import { IPynbImporter } from "@cocalc/jupyter/ipynb/import-from-ipynb";7import { JUPYTER_MIMETYPES } from "@cocalc/jupyter/util/misc";8import { field_cmp } from "@cocalc/util/misc";910export interface KernelSpec {11language?: string;12display_name: string;13name: string;14}1516export interface CoCalcJupyter {17cellList: string[];18cells: { [id: string]: object };19cmOptions?: { [field: string]: any };20metadata?;21kernelspec: KernelSpec;22}2324export default function parse(content: string): CoCalcJupyter {25const ipynb = JSON.parse(content);26const importer = new IPynbImporter();27importer.import({28ipynb,29output_handler: (cell) => {30let k: number = 0;31return {32message: (content) => {33process(content);34cell.output[`${k}`] = content;35k += 1;36},37};38},39});4041const cells = importer.cells();42const cellList = sortedCellList(cells);43const cmOptions = getCMOptions(getMode(ipynb));44const kernelspec = ipynb.metadata?.kernelspec ?? {45display_name: "Unknown Kernel",46};47return { cells, cellList, cmOptions, kernelspec };48}4950export function getMode(ipynb): string {51return (52ipynb.metadata?.language_info?.codemirror_mode ??53ipynb.metadata?.language_info?.name ??54ipynb.metadata?.kernelspec?.language?.toLowerCase() ??55"python"56);57}5859export function getCMOptions(60mode: string | { name: string } | undefined | null,61) {62if (mode == null) {63mode = { name: "python" };64}65if (typeof mode === "string") {66mode = { name: mode };67}68if (mode.name.includes("python") || mode.name.includes("sage")) {69mode.name = "python";70} else if (mode.name === "gp") {71mode.name = "pari";72} else if (mode.name === "singular") {73mode.name = "clike"; // better than nothing74} else if (mode.name === "ihaskell") {75mode.name = "haskell";76}7778return {79mode,80showTrailingSpace: true,81tabSize: 4,82lineWrapping: true,83readOnly: true,84};85}8687function process(content): void {88if (content?.data == null) {89return;90}91for (const type of JUPYTER_MIMETYPES) {92if (93content.data[type] != null &&94(type.split("/")[0] === "image" || type === "application/pdf")95) {96content.data[type] = { value: content.data[type] };97}98}99}100101function sortedCellList(cells): string[] {102// Given map from id's to cells, returns an list of ids in correct order,103// as defined by pos field.104const v: { id: string; pos: number }[] = [];105for (const id in cells) {106v.push({ id, pos: cells[id]?.pos ?? -1 });107}108v.sort(field_cmp("pos"));109const a: string[] = [];110for (const { id } of v) {111a.push(id);112}113return a;114}115116117