@deepnote/convert 1.2.0 → 1.3.0
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 +100 -23
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +114 -0
- package/dist/index.d.ts +148 -1
- package/dist/index.js +2 -86
- package/dist/src-j4HyYJfD.js +279 -0
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
# @deepnote/convert
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Bidirectional converter between Jupyter Notebook files (`.ipynb`) and Deepnote project files (`.deepnote`) with lossless roundtrip support.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# Convert a Jupyter notebook to a Deepnote project
|
|
7
|
+
npx @deepnote/convert notebook.ipynb
|
|
8
|
+
|
|
9
|
+
# Convert a Deepnote project to Jupyter notebooks
|
|
10
|
+
npx @deepnote/convert project.deepnote
|
|
11
|
+
```
|
|
4
12
|
|
|
5
13
|
## Installation
|
|
6
14
|
|
|
7
15
|
```bash
|
|
8
|
-
npm install @deepnote/convert
|
|
16
|
+
npm install -g @deepnote/convert
|
|
9
17
|
```
|
|
10
18
|
|
|
11
19
|
## CLI Usage
|
|
12
20
|
|
|
13
|
-
The package provides a `deepnote-convert` command-line tool for
|
|
21
|
+
The package provides a `deepnote-convert` command-line tool for bidirectional conversion between Jupyter and Deepnote formats.
|
|
22
|
+
|
|
23
|
+
### Convert Jupyter → Deepnote
|
|
14
24
|
|
|
15
|
-
|
|
25
|
+
#### Convert a Single Notebook
|
|
16
26
|
|
|
17
27
|
Convert a single `.ipynb` file to a `.deepnote` file:
|
|
18
28
|
|
|
@@ -22,7 +32,7 @@ deepnote-convert path/to/notebook.ipynb
|
|
|
22
32
|
|
|
23
33
|
This will create a `notebook.deepnote` file in the current directory.
|
|
24
34
|
|
|
25
|
-
|
|
35
|
+
#### Convert a Directory of Notebooks
|
|
26
36
|
|
|
27
37
|
Convert all `.ipynb` files in a directory to a single `.deepnote` project:
|
|
28
38
|
|
|
@@ -32,6 +42,16 @@ deepnote-convert path/to/notebooks/
|
|
|
32
42
|
|
|
33
43
|
This will create a `notebooks.deepnote` file in the current directory containing all notebooks from the directory.
|
|
34
44
|
|
|
45
|
+
### Convert Deepnote → Jupyter
|
|
46
|
+
|
|
47
|
+
Convert a `.deepnote` file to Jupyter notebooks:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
deepnote-convert path/to/project.deepnote
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
This will create a `project/` directory containing separate `.ipynb` files for each notebook in the Deepnote project.
|
|
54
|
+
|
|
35
55
|
### Options
|
|
36
56
|
|
|
37
57
|
#### `--projectName <name>`
|
|
@@ -46,49 +66,106 @@ If not specified, the project name will default to the filename (without extensi
|
|
|
46
66
|
|
|
47
67
|
#### `-o, --outputPath <path>`
|
|
48
68
|
|
|
49
|
-
Specify where to save the output
|
|
69
|
+
Specify where to save the output file(s):
|
|
50
70
|
|
|
51
71
|
```bash
|
|
52
|
-
# Save to a specific file
|
|
72
|
+
# For Jupyter → Deepnote: Save to a specific file
|
|
53
73
|
deepnote-convert notebook.ipynb -o output/project.deepnote
|
|
54
74
|
|
|
55
|
-
# Save to a directory (filename will be auto-generated)
|
|
75
|
+
# For Jupyter → Deepnote: Save to a directory (filename will be auto-generated)
|
|
56
76
|
deepnote-convert notebook.ipynb -o output/
|
|
77
|
+
|
|
78
|
+
# For Deepnote → Jupyter: Specify output directory for notebooks
|
|
79
|
+
deepnote-convert project.deepnote -o output/jupyter-notebooks/
|
|
57
80
|
```
|
|
58
81
|
|
|
59
|
-
If not specified
|
|
82
|
+
If not specified:
|
|
83
|
+
|
|
84
|
+
- For Jupyter → Deepnote: Output file will be saved in the current directory
|
|
85
|
+
- For Deepnote → Jupyter: A directory will be created using the `.deepnote` filename (e.g., `project.deepnote` → `project/`)
|
|
60
86
|
|
|
61
87
|
### Examples
|
|
62
88
|
|
|
63
89
|
```bash
|
|
64
|
-
# Convert a single notebook with custom name
|
|
90
|
+
# Jupyter → Deepnote: Convert a single notebook with custom name
|
|
65
91
|
deepnote-convert titanic.ipynb --projectName "Titanic Analysis"
|
|
66
92
|
|
|
67
|
-
# Convert all notebooks in a directory
|
|
93
|
+
# Jupyter → Deepnote: Convert all notebooks in a directory
|
|
68
94
|
deepnote-convert ./analysis --projectName "Data Science Project" -o ./output
|
|
69
95
|
|
|
70
|
-
# Convert multiple notebooks from a folder
|
|
96
|
+
# Jupyter → Deepnote: Convert multiple notebooks from a folder
|
|
71
97
|
deepnote-convert ~/notebooks/ml-experiments -o ~/projects/
|
|
98
|
+
|
|
99
|
+
# Deepnote → Jupyter: Convert a Deepnote project to Jupyter notebooks
|
|
100
|
+
deepnote-convert my-project.deepnote
|
|
101
|
+
|
|
102
|
+
# Deepnote → Jupyter: Specify output directory
|
|
103
|
+
deepnote-convert my-project.deepnote -o ./jupyter-notebooks/
|
|
72
104
|
```
|
|
73
105
|
|
|
106
|
+
### Lossless Roundtrip Conversion
|
|
107
|
+
|
|
108
|
+
The converter supports lossless roundtrip conversions:
|
|
109
|
+
|
|
110
|
+
- **Deepnote → Jupyter → Deepnote**: Preserves all Deepnote-specific metadata in Jupyter cell metadata, enabling faithful reconstruction of the original notebook's structure and metadata (note: serialization formatting or key ordering may differ)
|
|
111
|
+
- **Jupyter → Deepnote → Jupyter**: Preserves original Jupyter content while adding Deepnote metadata
|
|
112
|
+
|
|
113
|
+
This is achieved by storing Deepnote-specific metadata as flat `deepnote_*` keys directly on Jupyter notebook metadata (e.g., `deepnote_notebook_id`, `deepnote_execution_mode`) and cell metadata (e.g., `deepnote_cell_type`, `deepnote_sorting_key`, `deepnote_source`).
|
|
114
|
+
|
|
74
115
|
## Programmatic Usage
|
|
75
116
|
|
|
76
|
-
You can also use the conversion
|
|
117
|
+
You can also use the conversion functions programmatically in your Node.js or TypeScript applications.
|
|
77
118
|
|
|
78
|
-
###
|
|
119
|
+
### Jupyter → Deepnote
|
|
79
120
|
|
|
80
121
|
```typescript
|
|
81
|
-
import { convertIpynbFilesToDeepnoteFile } from
|
|
122
|
+
import { convertIpynbFilesToDeepnoteFile } from "@deepnote/convert";
|
|
82
123
|
|
|
83
|
-
await convertIpynbFilesToDeepnoteFile(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
124
|
+
await convertIpynbFilesToDeepnoteFile(["path/to/notebook.ipynb"], {
|
|
125
|
+
outputPath: "output.deepnote",
|
|
126
|
+
projectName: "My Project",
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Deepnote → Jupyter
|
|
131
|
+
|
|
132
|
+
#### File-based Conversion
|
|
133
|
+
|
|
134
|
+
For automatic file I/O (reading and writing files):
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { convertDeepnoteFileToJupyter } from "@deepnote/convert";
|
|
138
|
+
|
|
139
|
+
await convertDeepnoteFileToJupyter("path/to/project.deepnote", {
|
|
140
|
+
outputDir: "./jupyter-notebooks",
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### Pure Conversion (No File I/O)
|
|
145
|
+
|
|
146
|
+
For programmatic use with in-memory data:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import fs from "node:fs/promises";
|
|
150
|
+
import { deserializeDeepnoteFile } from "@deepnote/blocks";
|
|
151
|
+
import { convertDeepnoteToJupyterNotebooks } from "@deepnote/convert";
|
|
152
|
+
|
|
153
|
+
// Read and deserialize the Deepnote file
|
|
154
|
+
const yamlContent = await fs.readFile("project.deepnote", "utf-8");
|
|
155
|
+
const deepnoteFile = deserializeDeepnoteFile(yamlContent);
|
|
156
|
+
|
|
157
|
+
// Convert to Jupyter notebooks (pure function, no I/O)
|
|
158
|
+
const notebooks = convertDeepnoteToJupyterNotebooks(deepnoteFile);
|
|
159
|
+
|
|
160
|
+
// Now you can work with the notebooks in memory
|
|
161
|
+
for (const { filename, notebook } of notebooks) {
|
|
162
|
+
console.log(`${filename}: ${notebook.cells.length} cells`);
|
|
163
|
+
|
|
164
|
+
// Or save them yourself
|
|
165
|
+
await fs.writeFile(filename, JSON.stringify(notebook, null, 2));
|
|
166
|
+
}
|
|
167
|
+
```
|
|
90
168
|
|
|
91
169
|
## License
|
|
92
170
|
|
|
93
171
|
Apache-2.0
|
|
94
|
-
```
|
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as convertDeepnoteFileToJupyterFiles, t as convertIpynbFilesToDeepnoteFile } from "./src-j4HyYJfD.js";
|
|
3
|
+
import { cli } from "cleye";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import { basename, extname, resolve } from "node:path";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import ora from "ora";
|
|
8
|
+
|
|
9
|
+
//#region src/cli.ts
|
|
10
|
+
async function convert(options) {
|
|
11
|
+
const { inputPath, projectName: customProjectName, outputPath: customOutputPath, cwd = process.cwd() } = options;
|
|
12
|
+
const resolveProjectName = (possibleName) => {
|
|
13
|
+
if (customProjectName) return customProjectName;
|
|
14
|
+
if (possibleName) return possibleName;
|
|
15
|
+
return "Untitled project";
|
|
16
|
+
};
|
|
17
|
+
const resolveOutputPath = async (outputFilename) => {
|
|
18
|
+
if (customOutputPath) {
|
|
19
|
+
const absoluteOutputPath = resolve(cwd, customOutputPath);
|
|
20
|
+
if ((await fs.stat(absoluteOutputPath).catch(() => null))?.isDirectory()) return resolve(absoluteOutputPath, outputFilename);
|
|
21
|
+
return absoluteOutputPath;
|
|
22
|
+
}
|
|
23
|
+
return resolve(cwd, outputFilename);
|
|
24
|
+
};
|
|
25
|
+
const absolutePath = resolve(cwd, inputPath);
|
|
26
|
+
if ((await fs.stat(absolutePath)).isDirectory()) {
|
|
27
|
+
const ipynbFiles = (await fs.readdir(absolutePath, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".ipynb")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
|
|
28
|
+
if (ipynbFiles.length === 0) throw new Error("No .ipynb files found in the specified directory.");
|
|
29
|
+
const spinner = ora("Converting Jupyter Notebooks to a Deepnote project...").start();
|
|
30
|
+
try {
|
|
31
|
+
const filenameWithoutExtension = basename(absolutePath);
|
|
32
|
+
const projectName = resolveProjectName(filenameWithoutExtension);
|
|
33
|
+
const outputPath = await resolveOutputPath(`${filenameWithoutExtension}.deepnote`);
|
|
34
|
+
await convertIpynbFilesToDeepnoteFile(ipynbFiles.map((file) => resolve(absolutePath, file)), {
|
|
35
|
+
projectName,
|
|
36
|
+
outputPath
|
|
37
|
+
});
|
|
38
|
+
spinner.succeed(`The Deepnote project has been saved to ${chalk.bold(outputPath)}`);
|
|
39
|
+
return outputPath;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
spinner.fail("Conversion failed");
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const ext = extname(absolutePath).toLowerCase();
|
|
46
|
+
if (ext === ".ipynb") {
|
|
47
|
+
const spinner = ora("Converting the Jupyter Notebook to a Deepnote project...").start();
|
|
48
|
+
try {
|
|
49
|
+
const filenameWithoutExtension = basename(absolutePath, ext);
|
|
50
|
+
const projectName = resolveProjectName(filenameWithoutExtension);
|
|
51
|
+
const outputPath = await resolveOutputPath(`${filenameWithoutExtension}.deepnote`);
|
|
52
|
+
await convertIpynbFilesToDeepnoteFile([absolutePath], {
|
|
53
|
+
projectName,
|
|
54
|
+
outputPath
|
|
55
|
+
});
|
|
56
|
+
spinner.succeed(`The Deepnote project has been saved to ${chalk.bold(outputPath)}`);
|
|
57
|
+
return outputPath;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
spinner.fail("Conversion failed");
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (ext === ".deepnote") {
|
|
64
|
+
const spinner = ora("Converting Deepnote project to Jupyter Notebooks...").start();
|
|
65
|
+
try {
|
|
66
|
+
const outputDirName = basename(absolutePath, ext);
|
|
67
|
+
const outputDir = customOutputPath ? resolve(cwd, customOutputPath) : resolve(cwd, outputDirName);
|
|
68
|
+
await convertDeepnoteFileToJupyterFiles(absolutePath, { outputDir });
|
|
69
|
+
spinner.succeed(`Jupyter Notebooks have been saved to ${chalk.bold(outputDir)}`);
|
|
70
|
+
return outputDir;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
spinner.fail("Conversion failed");
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
throw new Error("Unsupported file type. Please provide a .ipynb or .deepnote file.");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/bin.ts
|
|
81
|
+
async function main() {
|
|
82
|
+
const argv = cli({
|
|
83
|
+
name: "deepnote-convert",
|
|
84
|
+
parameters: ["<path>"],
|
|
85
|
+
flags: {
|
|
86
|
+
projectName: {
|
|
87
|
+
description: "The name of the Deepnote project.",
|
|
88
|
+
type: String
|
|
89
|
+
},
|
|
90
|
+
outputPath: {
|
|
91
|
+
alias: "o",
|
|
92
|
+
description: "The path where the .deepnote file will be saved.",
|
|
93
|
+
type: String
|
|
94
|
+
},
|
|
95
|
+
cwd: {
|
|
96
|
+
description: "The working directory to resolve paths relative to.",
|
|
97
|
+
type: String
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
await convert({
|
|
102
|
+
inputPath: argv._.path,
|
|
103
|
+
projectName: argv.flags.projectName,
|
|
104
|
+
outputPath: argv.flags.outputPath,
|
|
105
|
+
cwd: argv.flags.cwd ?? process.cwd()
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
if (process.env.NODE_ENV !== "test" && process.env.VITEST !== "true") main().catch((error) => {
|
|
109
|
+
console.error(error);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
//#endregion
|
|
114
|
+
export { };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,158 @@
|
|
|
1
|
+
import { DeepnoteBlock, DeepnoteFile } from "@deepnote/blocks";
|
|
2
|
+
|
|
3
|
+
//#region src/types/jupyter.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Shared Jupyter Notebook type definitions used by both
|
|
7
|
+
* deepnote-to-jupyter and jupyter-to-deepnote converters.
|
|
8
|
+
*/
|
|
9
|
+
interface JupyterCell {
|
|
10
|
+
/** Top-level block_group field present in cloud-exported notebooks */
|
|
11
|
+
block_group?: string;
|
|
12
|
+
cell_type: 'code' | 'markdown';
|
|
13
|
+
execution_count?: number | null;
|
|
14
|
+
metadata: JupyterCellMetadata;
|
|
15
|
+
outputs?: any[];
|
|
16
|
+
outputs_reference?: string;
|
|
17
|
+
source: string | string[];
|
|
18
|
+
}
|
|
19
|
+
interface JupyterCellMetadata {
|
|
20
|
+
cell_id?: string;
|
|
21
|
+
deepnote_cell_type?: string;
|
|
22
|
+
deepnote_block_group?: string;
|
|
23
|
+
deepnote_sorting_key?: string;
|
|
24
|
+
deepnote_source?: string;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
interface JupyterNotebook {
|
|
28
|
+
cells: JupyterCell[];
|
|
29
|
+
metadata: JupyterNotebookMetadata;
|
|
30
|
+
nbformat?: number;
|
|
31
|
+
nbformat_minor?: number;
|
|
32
|
+
}
|
|
33
|
+
interface JupyterNotebookMetadata {
|
|
34
|
+
deepnote_notebook_id?: string;
|
|
35
|
+
deepnote_notebook_name?: string;
|
|
36
|
+
deepnote_execution_mode?: 'block' | 'downstream';
|
|
37
|
+
deepnote_is_module?: boolean;
|
|
38
|
+
deepnote_working_directory?: string;
|
|
39
|
+
[key: string]: unknown;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/deepnote-to-jupyter.d.ts
|
|
43
|
+
interface ConvertDeepnoteFileToJupyterOptions {
|
|
44
|
+
outputDir: string;
|
|
45
|
+
}
|
|
46
|
+
interface ConvertBlocksToJupyterOptions {
|
|
47
|
+
/** Unique identifier for the notebook */
|
|
48
|
+
notebookId: string;
|
|
49
|
+
/** Display name of the notebook */
|
|
50
|
+
notebookName: string;
|
|
51
|
+
/** Execution mode: 'block' runs cells individually, 'downstream' runs dependent cells */
|
|
52
|
+
executionMode?: 'block' | 'downstream';
|
|
53
|
+
/** Whether this notebook is a module (importable by other notebooks) */
|
|
54
|
+
isModule?: boolean;
|
|
55
|
+
/** Working directory for the notebook */
|
|
56
|
+
workingDirectory?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Converts an array of Deepnote blocks into a single Jupyter Notebook.
|
|
60
|
+
* This is the lowest-level conversion function, suitable for use in Deepnote Cloud.
|
|
61
|
+
*
|
|
62
|
+
* @param blocks - Array of DeepnoteBlock objects to convert
|
|
63
|
+
* @param options - Notebook metadata options
|
|
64
|
+
* @returns A JupyterNotebook object
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* import { convertBlocksToJupyterNotebook } from '@deepnote/convert'
|
|
69
|
+
*
|
|
70
|
+
* const notebook = convertBlocksToJupyterNotebook(blocks, {
|
|
71
|
+
* notebookId: 'abc123',
|
|
72
|
+
* notebookName: 'My Notebook',
|
|
73
|
+
* executionMode: 'block'
|
|
74
|
+
* })
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
declare function convertBlocksToJupyterNotebook(blocks: DeepnoteBlock[], options: ConvertBlocksToJupyterOptions): JupyterNotebook;
|
|
78
|
+
/**
|
|
79
|
+
* Converts a Deepnote project into Jupyter Notebook objects.
|
|
80
|
+
* This is a pure conversion function that doesn't perform any file I/O.
|
|
81
|
+
* Each notebook in the Deepnote project is converted to a separate Jupyter notebook.
|
|
82
|
+
*
|
|
83
|
+
* @param deepnoteFile - The deserialized Deepnote project file
|
|
84
|
+
* @returns Array of objects containing filename and corresponding Jupyter notebook
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* import { deserializeDeepnoteFile } from '@deepnote/blocks'
|
|
89
|
+
* import { convertDeepnoteToJupyterNotebooks } from '@deepnote/convert'
|
|
90
|
+
*
|
|
91
|
+
* const yamlContent = await fs.readFile('project.deepnote', 'utf-8')
|
|
92
|
+
* const deepnoteFile = deserializeDeepnoteFile(yamlContent)
|
|
93
|
+
* const notebooks = convertDeepnoteToJupyterNotebooks(deepnoteFile)
|
|
94
|
+
*
|
|
95
|
+
* for (const { filename, notebook } of notebooks) {
|
|
96
|
+
* console.log(`${filename}: ${notebook.cells.length} cells`)
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
declare function convertDeepnoteToJupyterNotebooks(deepnoteFile: DeepnoteFile): Array<{
|
|
101
|
+
filename: string;
|
|
102
|
+
notebook: JupyterNotebook;
|
|
103
|
+
}>;
|
|
104
|
+
/**
|
|
105
|
+
* Converts a Deepnote project file into separate Jupyter Notebook (.ipynb) files.
|
|
106
|
+
* Each notebook in the Deepnote project becomes a separate .ipynb file.
|
|
107
|
+
*/
|
|
108
|
+
declare function convertDeepnoteFileToJupyterFiles(deepnoteFilePath: string, options: ConvertDeepnoteFileToJupyterOptions): Promise<void>;
|
|
109
|
+
//#endregion
|
|
1
110
|
//#region src/jupyter-to-deepnote.d.ts
|
|
2
111
|
interface ConvertIpynbFilesToDeepnoteFileOptions {
|
|
3
112
|
outputPath: string;
|
|
4
113
|
projectName: string;
|
|
5
114
|
}
|
|
115
|
+
interface ConvertJupyterNotebookOptions {
|
|
116
|
+
/** Custom ID generator function. Defaults to uuid v4. */
|
|
117
|
+
idGenerator?: () => string;
|
|
118
|
+
}
|
|
119
|
+
interface JupyterNotebookInput {
|
|
120
|
+
filename: string;
|
|
121
|
+
notebook: JupyterNotebook;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Converts a single Jupyter Notebook into an array of Deepnote blocks.
|
|
125
|
+
* This is the lowest-level conversion function, suitable for use in Deepnote Cloud.
|
|
126
|
+
*
|
|
127
|
+
* @param notebook - The Jupyter notebook object to convert
|
|
128
|
+
* @param options - Optional conversion options including custom ID generator
|
|
129
|
+
* @returns Array of DeepnoteBlock objects
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* import { convertJupyterNotebookToBlocks } from '@deepnote/convert'
|
|
134
|
+
*
|
|
135
|
+
* const notebook = JSON.parse(ipynbContent)
|
|
136
|
+
* const blocks = convertJupyterNotebookToBlocks(notebook, {
|
|
137
|
+
* idGenerator: () => myCustomIdGenerator()
|
|
138
|
+
* })
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
declare function convertJupyterNotebookToBlocks(notebook: JupyterNotebook, options?: ConvertJupyterNotebookOptions): DeepnoteBlock[];
|
|
142
|
+
/**
|
|
143
|
+
* Converts Jupyter Notebook objects into a Deepnote project file.
|
|
144
|
+
* This is a pure conversion function that doesn't perform any file I/O.
|
|
145
|
+
*
|
|
146
|
+
* @param notebooks - Array of Jupyter notebooks with filenames
|
|
147
|
+
* @param options - Conversion options including project name
|
|
148
|
+
* @returns A DeepnoteFile object
|
|
149
|
+
*/
|
|
150
|
+
declare function convertJupyterNotebooksToDeepnote(notebooks: JupyterNotebookInput[], options: {
|
|
151
|
+
projectName: string;
|
|
152
|
+
}): DeepnoteFile;
|
|
6
153
|
/**
|
|
7
154
|
* Converts multiple Jupyter Notebook (.ipynb) files into a single Deepnote project file.
|
|
8
155
|
*/
|
|
9
156
|
declare function convertIpynbFilesToDeepnoteFile(inputFilePaths: string[], options: ConvertIpynbFilesToDeepnoteFileOptions): Promise<void>;
|
|
10
157
|
//#endregion
|
|
11
|
-
export { type ConvertIpynbFilesToDeepnoteFileOptions, convertIpynbFilesToDeepnoteFile };
|
|
158
|
+
export { type ConvertBlocksToJupyterOptions, type ConvertIpynbFilesToDeepnoteFileOptions, type ConvertJupyterNotebookOptions, type JupyterCell, type JupyterNotebook, type JupyterNotebookInput, convertBlocksToJupyterNotebook, convertDeepnoteFileToJupyterFiles as convertDeepnoteFileToJupyter, convertDeepnoteToJupyterNotebooks, convertIpynbFilesToDeepnoteFile, convertJupyterNotebookToBlocks, convertJupyterNotebooksToDeepnote };
|
package/dist/index.js
CHANGED
|
@@ -1,87 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { basename, dirname, extname } from "node:path";
|
|
3
|
-
import { v4 } from "uuid";
|
|
4
|
-
import { stringify } from "yaml";
|
|
1
|
+
import { a as convertDeepnoteFileToJupyterFiles, i as convertBlocksToJupyterNotebook, n as convertJupyterNotebookToBlocks, o as convertDeepnoteToJupyterNotebooks, r as convertJupyterNotebooksToDeepnote, t as convertIpynbFilesToDeepnoteFile } from "./src-j4HyYJfD.js";
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Converts multiple Jupyter Notebook (.ipynb) files into a single Deepnote project file.
|
|
9
|
-
*/
|
|
10
|
-
async function convertIpynbFilesToDeepnoteFile(inputFilePaths, options) {
|
|
11
|
-
const deepnoteFile = {
|
|
12
|
-
metadata: { createdAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
13
|
-
project: {
|
|
14
|
-
id: v4(),
|
|
15
|
-
initNotebookId: void 0,
|
|
16
|
-
integrations: [],
|
|
17
|
-
name: options.projectName,
|
|
18
|
-
notebooks: [],
|
|
19
|
-
settings: {}
|
|
20
|
-
},
|
|
21
|
-
version: "1.0.0"
|
|
22
|
-
};
|
|
23
|
-
for (const filePath of inputFilePaths) {
|
|
24
|
-
const name = basename(filePath, extname(filePath)) || "Untitled notebook";
|
|
25
|
-
const blocks = (await parseIpynbFile(filePath)).cells.map((cell, index) => {
|
|
26
|
-
const source = Array.isArray(cell.source) ? cell.source.join("") : cell.source;
|
|
27
|
-
return {
|
|
28
|
-
blockGroup: v4(),
|
|
29
|
-
content: source,
|
|
30
|
-
executionCount: cell.execution_count ?? void 0,
|
|
31
|
-
id: v4(),
|
|
32
|
-
metadata: {},
|
|
33
|
-
outputs: cell.cell_type === "code" ? cell.outputs : void 0,
|
|
34
|
-
sortingKey: createSortingKey(index),
|
|
35
|
-
type: cell.cell_type === "code" ? "code" : "markdown",
|
|
36
|
-
version: 1
|
|
37
|
-
};
|
|
38
|
-
});
|
|
39
|
-
deepnoteFile.project.notebooks.push({
|
|
40
|
-
blocks,
|
|
41
|
-
executionMode: "block",
|
|
42
|
-
id: v4(),
|
|
43
|
-
isModule: false,
|
|
44
|
-
name,
|
|
45
|
-
workingDirectory: void 0
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
const yamlContent = stringify(deepnoteFile);
|
|
49
|
-
const parentDir = dirname(options.outputPath);
|
|
50
|
-
await fs.mkdir(parentDir, { recursive: true });
|
|
51
|
-
await fs.writeFile(options.outputPath, yamlContent, "utf-8");
|
|
52
|
-
}
|
|
53
|
-
async function parseIpynbFile(filePath) {
|
|
54
|
-
let ipynbJson;
|
|
55
|
-
try {
|
|
56
|
-
ipynbJson = await fs.readFile(filePath, "utf-8");
|
|
57
|
-
} catch (error) {
|
|
58
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
59
|
-
throw new Error(`Failed to read ${filePath}: ${message}`);
|
|
60
|
-
}
|
|
61
|
-
try {
|
|
62
|
-
return JSON.parse(ipynbJson);
|
|
63
|
-
} catch (error) {
|
|
64
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
65
|
-
throw new Error(`Failed to parse ${filePath}: invalid JSON - ${message}`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function createSortingKey(index) {
|
|
69
|
-
const maxLength = 6;
|
|
70
|
-
const chars = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
71
|
-
const base = 36;
|
|
72
|
-
if (index < 0) throw new Error("Index must be non-negative");
|
|
73
|
-
let result = "";
|
|
74
|
-
let num = index + 1;
|
|
75
|
-
let iterations = 0;
|
|
76
|
-
while (num > 0 && iterations < maxLength) {
|
|
77
|
-
num--;
|
|
78
|
-
result = chars[num % base] + result;
|
|
79
|
-
num = Math.floor(num / base);
|
|
80
|
-
iterations++;
|
|
81
|
-
}
|
|
82
|
-
if (num > 0) throw new Error(`Index ${index} exceeds maximum key length of ${maxLength}`);
|
|
83
|
-
return result;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
//#endregion
|
|
87
|
-
export { convertIpynbFilesToDeepnoteFile };
|
|
3
|
+
export { convertBlocksToJupyterNotebook, convertDeepnoteFileToJupyterFiles as convertDeepnoteFileToJupyter, convertDeepnoteToJupyterNotebooks, convertIpynbFilesToDeepnoteFile, convertJupyterNotebookToBlocks, convertJupyterNotebooksToDeepnote };
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { basename, dirname, extname, join } from "node:path";
|
|
3
|
+
import { createMarkdown, createPythonCode, deserializeDeepnoteFile } from "@deepnote/blocks";
|
|
4
|
+
import { v4 } from "uuid";
|
|
5
|
+
import { stringify } from "yaml";
|
|
6
|
+
|
|
7
|
+
//#region src/deepnote-to-jupyter.ts
|
|
8
|
+
/**
|
|
9
|
+
* Converts an array of Deepnote blocks into a single Jupyter Notebook.
|
|
10
|
+
* This is the lowest-level conversion function, suitable for use in Deepnote Cloud.
|
|
11
|
+
*
|
|
12
|
+
* @param blocks - Array of DeepnoteBlock objects to convert
|
|
13
|
+
* @param options - Notebook metadata options
|
|
14
|
+
* @returns A JupyterNotebook object
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { convertBlocksToJupyterNotebook } from '@deepnote/convert'
|
|
19
|
+
*
|
|
20
|
+
* const notebook = convertBlocksToJupyterNotebook(blocks, {
|
|
21
|
+
* notebookId: 'abc123',
|
|
22
|
+
* notebookName: 'My Notebook',
|
|
23
|
+
* executionMode: 'block'
|
|
24
|
+
* })
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
function convertBlocksToJupyterNotebook(blocks, options) {
|
|
28
|
+
return {
|
|
29
|
+
cells: blocks.map((block) => convertBlockToCell(block)),
|
|
30
|
+
metadata: {
|
|
31
|
+
deepnote_notebook_id: options.notebookId,
|
|
32
|
+
deepnote_notebook_name: options.notebookName,
|
|
33
|
+
deepnote_execution_mode: options.executionMode,
|
|
34
|
+
deepnote_is_module: options.isModule,
|
|
35
|
+
deepnote_working_directory: options.workingDirectory
|
|
36
|
+
},
|
|
37
|
+
nbformat: 4,
|
|
38
|
+
nbformat_minor: 0
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Converts a Deepnote project into Jupyter Notebook objects.
|
|
43
|
+
* This is a pure conversion function that doesn't perform any file I/O.
|
|
44
|
+
* Each notebook in the Deepnote project is converted to a separate Jupyter notebook.
|
|
45
|
+
*
|
|
46
|
+
* @param deepnoteFile - The deserialized Deepnote project file
|
|
47
|
+
* @returns Array of objects containing filename and corresponding Jupyter notebook
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* import { deserializeDeepnoteFile } from '@deepnote/blocks'
|
|
52
|
+
* import { convertDeepnoteToJupyterNotebooks } from '@deepnote/convert'
|
|
53
|
+
*
|
|
54
|
+
* const yamlContent = await fs.readFile('project.deepnote', 'utf-8')
|
|
55
|
+
* const deepnoteFile = deserializeDeepnoteFile(yamlContent)
|
|
56
|
+
* const notebooks = convertDeepnoteToJupyterNotebooks(deepnoteFile)
|
|
57
|
+
*
|
|
58
|
+
* for (const { filename, notebook } of notebooks) {
|
|
59
|
+
* console.log(`${filename}: ${notebook.cells.length} cells`)
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
function convertDeepnoteToJupyterNotebooks(deepnoteFile) {
|
|
64
|
+
return deepnoteFile.project.notebooks.map((notebook) => {
|
|
65
|
+
const jupyterNotebook = convertNotebookToJupyter(deepnoteFile, notebook);
|
|
66
|
+
return {
|
|
67
|
+
filename: `${sanitizeFileName(notebook.name)}.ipynb`,
|
|
68
|
+
notebook: jupyterNotebook
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Converts a Deepnote project file into separate Jupyter Notebook (.ipynb) files.
|
|
74
|
+
* Each notebook in the Deepnote project becomes a separate .ipynb file.
|
|
75
|
+
*/
|
|
76
|
+
async function convertDeepnoteFileToJupyterFiles(deepnoteFilePath, options) {
|
|
77
|
+
const notebooks = convertDeepnoteToJupyterNotebooks(deserializeDeepnoteFile(await fs.readFile(deepnoteFilePath, "utf-8")));
|
|
78
|
+
await fs.mkdir(options.outputDir, { recursive: true });
|
|
79
|
+
for (const { filename, notebook } of notebooks) {
|
|
80
|
+
const filePath = join(options.outputDir, filename);
|
|
81
|
+
await fs.writeFile(filePath, JSON.stringify(notebook, null, 2), "utf-8");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function convertBlockToCell(block) {
|
|
85
|
+
const content = block.content || "";
|
|
86
|
+
const jupyterCellType = convertBlockTypeToJupyter(block.type);
|
|
87
|
+
const metadata = {
|
|
88
|
+
cell_id: block.id,
|
|
89
|
+
deepnote_block_group: block.blockGroup,
|
|
90
|
+
deepnote_cell_type: block.type,
|
|
91
|
+
deepnote_sorting_key: block.sortingKey,
|
|
92
|
+
...block.metadata || {}
|
|
93
|
+
};
|
|
94
|
+
metadata.deepnote_source = content;
|
|
95
|
+
return {
|
|
96
|
+
block_group: block.blockGroup,
|
|
97
|
+
cell_type: jupyterCellType,
|
|
98
|
+
execution_count: block.executionCount ?? null,
|
|
99
|
+
metadata,
|
|
100
|
+
outputs: block.outputs,
|
|
101
|
+
source: getSourceForBlock(block, jupyterCellType, content)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function getSourceForBlock(block, jupyterCellType, content) {
|
|
105
|
+
if (jupyterCellType === "markdown") return createMarkdown(block);
|
|
106
|
+
if (block.type === "code") return content;
|
|
107
|
+
return createPythonCode(block);
|
|
108
|
+
}
|
|
109
|
+
function convertBlockTypeToJupyter(blockType) {
|
|
110
|
+
const codeTypes = [
|
|
111
|
+
"big-number",
|
|
112
|
+
"button",
|
|
113
|
+
"code",
|
|
114
|
+
"notebook-function",
|
|
115
|
+
"sql",
|
|
116
|
+
"visualization"
|
|
117
|
+
];
|
|
118
|
+
if (blockType.startsWith("input-")) return "code";
|
|
119
|
+
return codeTypes.includes(blockType) ? "code" : "markdown";
|
|
120
|
+
}
|
|
121
|
+
function convertNotebookToJupyter(_deepnoteFile, notebook) {
|
|
122
|
+
return convertBlocksToJupyterNotebook(notebook.blocks, {
|
|
123
|
+
notebookId: notebook.id,
|
|
124
|
+
notebookName: notebook.name,
|
|
125
|
+
executionMode: notebook.executionMode,
|
|
126
|
+
isModule: notebook.isModule,
|
|
127
|
+
workingDirectory: notebook.workingDirectory
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function sanitizeFileName(name) {
|
|
131
|
+
return name.replace(/[<>:"/\\|?*]/g, "_").replace(/\s+/g, "-");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/jupyter-to-deepnote.ts
|
|
136
|
+
/**
|
|
137
|
+
* Converts a single Jupyter Notebook into an array of Deepnote blocks.
|
|
138
|
+
* This is the lowest-level conversion function, suitable for use in Deepnote Cloud.
|
|
139
|
+
*
|
|
140
|
+
* @param notebook - The Jupyter notebook object to convert
|
|
141
|
+
* @param options - Optional conversion options including custom ID generator
|
|
142
|
+
* @returns Array of DeepnoteBlock objects
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* import { convertJupyterNotebookToBlocks } from '@deepnote/convert'
|
|
147
|
+
*
|
|
148
|
+
* const notebook = JSON.parse(ipynbContent)
|
|
149
|
+
* const blocks = convertJupyterNotebookToBlocks(notebook, {
|
|
150
|
+
* idGenerator: () => myCustomIdGenerator()
|
|
151
|
+
* })
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
function convertJupyterNotebookToBlocks(notebook, options) {
|
|
155
|
+
const idGenerator = options?.idGenerator ?? v4;
|
|
156
|
+
return notebook.cells.map((cell, index) => convertCellToBlock(cell, index, idGenerator));
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Converts Jupyter Notebook objects into a Deepnote project file.
|
|
160
|
+
* This is a pure conversion function that doesn't perform any file I/O.
|
|
161
|
+
*
|
|
162
|
+
* @param notebooks - Array of Jupyter notebooks with filenames
|
|
163
|
+
* @param options - Conversion options including project name
|
|
164
|
+
* @returns A DeepnoteFile object
|
|
165
|
+
*/
|
|
166
|
+
function convertJupyterNotebooksToDeepnote(notebooks, options) {
|
|
167
|
+
const deepnoteFile = {
|
|
168
|
+
metadata: { createdAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
169
|
+
project: {
|
|
170
|
+
id: v4(),
|
|
171
|
+
initNotebookId: void 0,
|
|
172
|
+
integrations: [],
|
|
173
|
+
name: options.projectName,
|
|
174
|
+
notebooks: [],
|
|
175
|
+
settings: {}
|
|
176
|
+
},
|
|
177
|
+
version: "1.0.0"
|
|
178
|
+
};
|
|
179
|
+
for (const { filename, notebook } of notebooks) {
|
|
180
|
+
const filenameWithoutExt = basename(filename, extname(filename)) || "Untitled notebook";
|
|
181
|
+
const blocks = convertJupyterNotebookToBlocks(notebook);
|
|
182
|
+
const notebookId = notebook.metadata?.deepnote_notebook_id;
|
|
183
|
+
const notebookName = notebook.metadata?.deepnote_notebook_name;
|
|
184
|
+
const executionMode = notebook.metadata?.deepnote_execution_mode;
|
|
185
|
+
const isModule = notebook.metadata?.deepnote_is_module;
|
|
186
|
+
const workingDirectory = notebook.metadata?.deepnote_working_directory;
|
|
187
|
+
deepnoteFile.project.notebooks.push({
|
|
188
|
+
blocks,
|
|
189
|
+
executionMode: executionMode ?? "block",
|
|
190
|
+
id: notebookId ?? v4(),
|
|
191
|
+
isModule: isModule ?? false,
|
|
192
|
+
name: notebookName ?? filenameWithoutExt,
|
|
193
|
+
workingDirectory
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
return deepnoteFile;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Converts multiple Jupyter Notebook (.ipynb) files into a single Deepnote project file.
|
|
200
|
+
*/
|
|
201
|
+
async function convertIpynbFilesToDeepnoteFile(inputFilePaths, options) {
|
|
202
|
+
const notebooks = [];
|
|
203
|
+
for (const filePath of inputFilePaths) {
|
|
204
|
+
const notebook = await parseIpynbFile(filePath);
|
|
205
|
+
notebooks.push({
|
|
206
|
+
filename: basename(filePath),
|
|
207
|
+
notebook
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
const yamlContent = stringify(convertJupyterNotebooksToDeepnote(notebooks, { projectName: options.projectName }));
|
|
211
|
+
const parentDir = dirname(options.outputPath);
|
|
212
|
+
await fs.mkdir(parentDir, { recursive: true });
|
|
213
|
+
await fs.writeFile(options.outputPath, yamlContent, "utf-8");
|
|
214
|
+
}
|
|
215
|
+
async function parseIpynbFile(filePath) {
|
|
216
|
+
let ipynbJson;
|
|
217
|
+
try {
|
|
218
|
+
ipynbJson = await fs.readFile(filePath, "utf-8");
|
|
219
|
+
} catch (error) {
|
|
220
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
221
|
+
throw new Error(`Failed to read ${filePath}: ${message}`);
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
return JSON.parse(ipynbJson);
|
|
225
|
+
} catch (error) {
|
|
226
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
227
|
+
throw new Error(`Failed to parse ${filePath}: invalid JSON - ${message}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function convertCellToBlock(cell, index, idGenerator) {
|
|
231
|
+
let source = Array.isArray(cell.source) ? cell.source.join("") : cell.source;
|
|
232
|
+
const cellId = cell.metadata?.cell_id;
|
|
233
|
+
const deepnoteCellType = cell.metadata?.deepnote_cell_type;
|
|
234
|
+
const sortingKey = cell.metadata?.deepnote_sorting_key;
|
|
235
|
+
const blockGroup = cell.metadata?.deepnote_block_group ?? cell.block_group ?? idGenerator();
|
|
236
|
+
const deepnoteSource = cell.metadata?.deepnote_source;
|
|
237
|
+
if (deepnoteSource !== void 0) source = deepnoteSource;
|
|
238
|
+
const blockType = deepnoteCellType ?? (cell.cell_type === "code" ? "code" : "markdown");
|
|
239
|
+
const originalMetadata = { ...cell.metadata };
|
|
240
|
+
delete originalMetadata.cell_id;
|
|
241
|
+
delete originalMetadata.deepnote_cell_type;
|
|
242
|
+
delete originalMetadata.deepnote_block_group;
|
|
243
|
+
delete originalMetadata.deepnote_sorting_key;
|
|
244
|
+
delete originalMetadata.deepnote_source;
|
|
245
|
+
delete cell.block_group;
|
|
246
|
+
const executionCount = cell.execution_count ?? void 0;
|
|
247
|
+
const hasExecutionCount = executionCount !== void 0;
|
|
248
|
+
const hasOutputs = cell.cell_type === "code" && cell.outputs !== void 0;
|
|
249
|
+
return {
|
|
250
|
+
blockGroup,
|
|
251
|
+
content: source,
|
|
252
|
+
...hasExecutionCount ? { executionCount } : {},
|
|
253
|
+
id: cellId ?? idGenerator(),
|
|
254
|
+
metadata: originalMetadata,
|
|
255
|
+
...hasOutputs ? { outputs: cell.outputs } : {},
|
|
256
|
+
sortingKey: sortingKey ?? createSortingKey(index),
|
|
257
|
+
type: blockType
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function createSortingKey(index) {
|
|
261
|
+
const maxLength = 6;
|
|
262
|
+
const chars = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
263
|
+
const base = 36;
|
|
264
|
+
if (index < 0) throw new Error("Index must be non-negative");
|
|
265
|
+
let result = "";
|
|
266
|
+
let num = index + 1;
|
|
267
|
+
let iterations = 0;
|
|
268
|
+
while (num > 0 && iterations < maxLength) {
|
|
269
|
+
num--;
|
|
270
|
+
result = chars[num % base] + result;
|
|
271
|
+
num = Math.floor(num / base);
|
|
272
|
+
iterations++;
|
|
273
|
+
}
|
|
274
|
+
if (num > 0) throw new Error(`Index ${index} exceeds maximum key length of ${maxLength}`);
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
//#endregion
|
|
279
|
+
export { convertDeepnoteFileToJupyterFiles as a, convertBlocksToJupyterNotebook as i, convertJupyterNotebookToBlocks as n, convertDeepnoteToJupyterNotebooks as o, convertJupyterNotebooksToDeepnote as r, convertIpynbFilesToDeepnoteFile as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepnote/convert",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"repository": {
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"chalk": "^5.6.2",
|
|
32
|
-
"cleye": "^
|
|
32
|
+
"cleye": "^2.0.0",
|
|
33
33
|
"ora": "^9.0.0",
|
|
34
34
|
"uuid": "^13.0.0",
|
|
35
35
|
"yaml": "^2.8.1",
|
|
36
|
-
"@deepnote/blocks": "1.3.
|
|
36
|
+
"@deepnote/blocks": "1.3.6"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^22.0.0",
|
|
@@ -41,15 +41,16 @@
|
|
|
41
41
|
"typescript": "^5.0.0"
|
|
42
42
|
},
|
|
43
43
|
"engines": {
|
|
44
|
-
"node": ">=
|
|
44
|
+
"node": ">=22.14.0",
|
|
45
|
+
"pnpm": ">=10.17.1"
|
|
45
46
|
},
|
|
46
47
|
"publishConfig": {
|
|
47
48
|
"access": "public",
|
|
48
49
|
"registry": "https://registry.npmjs.org"
|
|
49
50
|
},
|
|
50
51
|
"scripts": {
|
|
51
|
-
"build": "tsdown --format esm --dts",
|
|
52
|
+
"build": "tsdown --format esm --dts src/bin.ts src/index.ts",
|
|
52
53
|
"test": "vitest",
|
|
53
|
-
"watch": "tsdown --watch --format esm --dts"
|
|
54
|
+
"watch": "tsdown --watch --format esm --dts src/bin.ts src/index.ts"
|
|
54
55
|
}
|
|
55
56
|
}
|