Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/ipynb/src/notebookSerializer.ts
3292 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import type * as nbformat from '@jupyterlab/nbformat';
7
import detectIndent from 'detect-indent';
8
import * as vscode from 'vscode';
9
import { getPreferredLanguage, jupyterNotebookModelToNotebookData } from './deserializers';
10
import * as fnv from '@enonic/fnv-plus';
11
import { serializeNotebookToString } from './serializers';
12
13
export abstract class NotebookSerializerBase extends vscode.Disposable implements vscode.NotebookSerializer {
14
protected disposed: boolean = false;
15
constructor(protected readonly context: vscode.ExtensionContext) {
16
super(() => { });
17
}
18
19
override dispose() {
20
this.disposed = true;
21
super.dispose();
22
}
23
24
public async deserializeNotebook(content: Uint8Array, _token: vscode.CancellationToken): Promise<vscode.NotebookData> {
25
let contents = '';
26
try {
27
contents = new TextDecoder().decode(content);
28
} catch {
29
}
30
31
let json = contents && /\S/.test(contents) ? (JSON.parse(contents) as Partial<nbformat.INotebookContent>) : {};
32
33
if (json.__webview_backup) {
34
const backupId = json.__webview_backup;
35
const uri = this.context.globalStorageUri;
36
const folder = uri.with({ path: this.context.globalStorageUri.path.replace('vscode.ipynb', 'ms-toolsai.jupyter') });
37
const fileHash = fnv.fast1a32hex(backupId) as string;
38
const fileName = `${fileHash}.ipynb`;
39
const file = vscode.Uri.joinPath(folder, fileName);
40
const data = await vscode.workspace.fs.readFile(file);
41
json = data ? JSON.parse(data.toString()) : {};
42
43
if (json.contents && typeof json.contents === 'string') {
44
contents = json.contents;
45
json = JSON.parse(contents) as Partial<nbformat.INotebookContent>;
46
}
47
}
48
49
if (json.nbformat && json.nbformat < 4) {
50
throw new Error('Only Jupyter notebooks version 4+ are supported');
51
}
52
53
// Then compute indent from the contents (only use first 1K characters as a perf optimization)
54
const indentAmount = contents ? detectIndent(contents.substring(0, 1_000)).indent : ' ';
55
56
const preferredCellLanguage = getPreferredLanguage(json.metadata);
57
// Ensure we always have a blank cell.
58
if ((json.cells || []).length === 0) {
59
json.cells = [
60
];
61
}
62
63
// For notebooks without metadata default the language in metadata to the preferred language.
64
if (!json.metadata || (!json.metadata.kernelspec && !json.metadata.language_info)) {
65
json.metadata = json.metadata || {};
66
json.metadata.language_info = json.metadata.language_info || { name: preferredCellLanguage };
67
}
68
69
const data = jupyterNotebookModelToNotebookData(
70
json,
71
preferredCellLanguage
72
);
73
data.metadata = data.metadata || {};
74
data.metadata.indentAmount = indentAmount;
75
76
return data;
77
}
78
79
public async serializeNotebook(data: vscode.NotebookData, _token: vscode.CancellationToken): Promise<Uint8Array> {
80
if (this.disposed) {
81
return new Uint8Array(0);
82
}
83
84
const serialized = serializeNotebookToString(data);
85
return new TextEncoder().encode(serialized);
86
}
87
88
}
89
90