@deepnote/convert 1.1.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 ADDED
@@ -0,0 +1,94 @@
1
+ # @deepnote/convert
2
+
3
+ Convert Jupyter Notebook files (`.ipynb`) to Deepnote project files (`.deepnote`).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @deepnote/convert
9
+ ```
10
+
11
+ ## CLI Usage
12
+
13
+ The package provides a `deepnote-convert` command-line tool for converting Jupyter notebooks to Deepnote format.
14
+
15
+ ### Convert a Single Notebook
16
+
17
+ Convert a single `.ipynb` file to a `.deepnote` file:
18
+
19
+ ```bash
20
+ deepnote-convert path/to/notebook.ipynb
21
+ ```
22
+
23
+ This will create a `notebook.deepnote` file in the current directory.
24
+
25
+ ### Convert a Directory of Notebooks
26
+
27
+ Convert all `.ipynb` files in a directory to a single `.deepnote` project:
28
+
29
+ ```bash
30
+ deepnote-convert path/to/notebooks/
31
+ ```
32
+
33
+ This will create a `notebooks.deepnote` file in the current directory containing all notebooks from the directory.
34
+
35
+ ### Options
36
+
37
+ #### `--projectName <name>`
38
+
39
+ Set a custom name for the Deepnote project:
40
+
41
+ ```bash
42
+ deepnote-convert notebook.ipynb --projectName "My Analysis"
43
+ ```
44
+
45
+ If not specified, the project name will default to the filename (without extension) or directory name.
46
+
47
+ #### `-o, --outputPath <path>`
48
+
49
+ Specify where to save the output `.deepnote` file:
50
+
51
+ ```bash
52
+ # Save to a specific file
53
+ deepnote-convert notebook.ipynb -o output/project.deepnote
54
+
55
+ # Save to a directory (filename will be auto-generated)
56
+ deepnote-convert notebook.ipynb -o output/
57
+ ```
58
+
59
+ If not specified, the output file will be saved in the current directory.
60
+
61
+ ### Examples
62
+
63
+ ```bash
64
+ # Convert a single notebook with custom name
65
+ deepnote-convert titanic.ipynb --projectName "Titanic Analysis"
66
+
67
+ # Convert all notebooks in a directory
68
+ deepnote-convert ./analysis --projectName "Data Science Project" -o ./output
69
+
70
+ # Convert multiple notebooks from a folder
71
+ deepnote-convert ~/notebooks/ml-experiments -o ~/projects/
72
+ ```
73
+
74
+ ## Programmatic Usage
75
+
76
+ You can also use the conversion function programmatically in your Node.js or TypeScript applications.
77
+
78
+ ### Basic Usage
79
+
80
+ ```typescript
81
+ import { convertIpynbFilesToDeepnoteFile } from '@deepnote/convert'
82
+
83
+ await convertIpynbFilesToDeepnoteFile(
84
+ ['path/to/notebook.ipynb'],
85
+ {
86
+ outputPath: 'output.deepnote',
87
+ projectName: 'My Project'
88
+ }
89
+ )
90
+
91
+ ## License
92
+
93
+ Apache-2.0
94
+ ```
@@ -0,0 +1,11 @@
1
+ //#region src/jupyter-to-deepnote.d.ts
2
+ interface ConvertIpynbFilesToDeepnoteFileOptions {
3
+ outputPath: string;
4
+ projectName: string;
5
+ }
6
+ /**
7
+ * Converts multiple Jupyter Notebook (.ipynb) files into a single Deepnote project file.
8
+ */
9
+ declare function convertIpynbFilesToDeepnoteFile(inputFilePaths: string[], options: ConvertIpynbFilesToDeepnoteFileOptions): Promise<void>;
10
+ //#endregion
11
+ export { type ConvertIpynbFilesToDeepnoteFileOptions, convertIpynbFilesToDeepnoteFile };
package/dist/index.js ADDED
@@ -0,0 +1,87 @@
1
+ import fs from "node:fs/promises";
2
+ import { basename, dirname, extname } from "node:path";
3
+ import { v4 } from "uuid";
4
+ import { stringify } from "yaml";
5
+
6
+ //#region src/jupyter-to-deepnote.ts
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 };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@deepnote/convert",
3
+ "version": "1.1.0",
4
+ "description": "",
5
+ "keywords": [],
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/deepnote/deepnote.git",
9
+ "directory": "packages/convert"
10
+ },
11
+ "license": "Apache-2.0",
12
+ "type": "module",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/index.js",
16
+ "types": "./dist/index.d.ts"
17
+ }
18
+ },
19
+ "main": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "bin": {
22
+ "deepnote-convert": "./dist/bin.js"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "README.md",
27
+ "LICENSE",
28
+ "package.json"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsdown --format esm --dts",
32
+ "test": "vitest",
33
+ "watch": "tsdown --watch --format esm --dts"
34
+ },
35
+ "dependencies": {
36
+ "@deepnote/blocks": "workspace:*",
37
+ "chalk": "^5.6.2",
38
+ "cleye": "^1.3.4",
39
+ "ora": "^9.0.0",
40
+ "uuid": "^13.0.0",
41
+ "yaml": "^2.8.1"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^22.0.0",
45
+ "tsx": "^4.20.6",
46
+ "typescript": "^5.0.0"
47
+ },
48
+ "engines": {
49
+ "node": ">=18"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public",
53
+ "registry": "https://registry.npmjs.org"
54
+ }
55
+ }