@deepnote/convert 2.1.3 → 2.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/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { DeepnoteBlock, DeepnoteFile, Environment, Execution } from "@deepnote/blocks";
1
+ import { DeepnoteBlock, DeepnoteFile, DeepnoteSnapshot, Environment, Execution } from "@deepnote/blocks";
2
2
 
3
3
  //#region src/types/jupyter.d.ts
4
4
 
@@ -6,6 +6,35 @@ import { DeepnoteBlock, DeepnoteFile, Environment, Execution } from "@deepnote/b
6
6
  * Shared Jupyter Notebook type definitions used by both
7
7
  * deepnote-to-jupyter and jupyter-to-deepnote converters.
8
8
  */
9
+ /**
10
+ * Jupyter output types - used for cell outputs.
11
+ */
12
+ interface JupyterOutputBase {
13
+ output_type: string;
14
+ }
15
+ interface JupyterStreamOutput extends JupyterOutputBase {
16
+ output_type: 'stream';
17
+ name: 'stdout' | 'stderr';
18
+ text: string | string[];
19
+ }
20
+ interface JupyterDisplayDataOutput extends JupyterOutputBase {
21
+ output_type: 'display_data';
22
+ data: Record<string, unknown>;
23
+ metadata?: Record<string, unknown>;
24
+ }
25
+ interface JupyterExecuteResultOutput extends JupyterOutputBase {
26
+ output_type: 'execute_result';
27
+ data: Record<string, unknown>;
28
+ metadata?: Record<string, unknown>;
29
+ execution_count?: number | null;
30
+ }
31
+ interface JupyterErrorOutput extends JupyterOutputBase {
32
+ output_type: 'error';
33
+ ename: string;
34
+ evalue: string;
35
+ traceback: string[];
36
+ }
37
+ type JupyterOutput = JupyterStreamOutput | JupyterDisplayDataOutput | JupyterExecuteResultOutput | JupyterErrorOutput;
9
38
  interface JupyterCell {
10
39
  /** Top-level block_group field present in cloud-exported notebooks */
11
40
  block_group?: string;
@@ -110,6 +139,27 @@ declare function convertDeepnoteToJupyterNotebooks(deepnoteFile: DeepnoteFile):
110
139
  * Each notebook in the Deepnote project becomes a separate .ipynb file.
111
140
  */
112
141
  declare function convertDeepnoteFileToJupyterFiles(deepnoteFilePath: string, options: ConvertDeepnoteFileToJupyterOptions): Promise<void>;
142
+ /**
143
+ * Converts a single Deepnote block to a Jupyter cell.
144
+ * This is useful for streaming export scenarios where blocks need to be
145
+ * processed one at a time rather than converting an entire notebook at once.
146
+ *
147
+ * @param block - A single DeepnoteBlock to convert
148
+ * @returns A JupyterCell object
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * import { convertBlockToJupyterCell } from '@deepnote/convert'
153
+ * import type { JupyterCell } from '@deepnote/convert'
154
+ *
155
+ * // Streaming export example
156
+ * for await (const block of blockStream) {
157
+ * const cell: JupyterCell = convertBlockToJupyterCell(block)
158
+ * outputStream.write(JSON.stringify(cell))
159
+ * }
160
+ * ```
161
+ */
162
+ declare function convertBlockToJupyterCell(block: DeepnoteBlock): JupyterCell;
113
163
  //#endregion
114
164
  //#region src/types/marimo.d.ts
115
165
  /**
@@ -408,6 +458,9 @@ interface ConvertIpynbFilesToDeepnoteFileOptions {
408
458
  outputPath: string;
409
459
  projectName: string;
410
460
  }
461
+ interface ReadAndConvertIpynbFilesOptions {
462
+ projectName: string;
463
+ }
411
464
  interface ConvertJupyterNotebookOptions {
412
465
  /** Custom ID generator function. Defaults to crypto.randomUUID(). */
413
466
  idGenerator?: () => string;
@@ -446,6 +499,15 @@ declare function convertJupyterNotebookToBlocks(notebook: JupyterNotebook, optio
446
499
  declare function convertJupyterNotebooksToDeepnote(notebooks: JupyterNotebookInput[], options: {
447
500
  projectName: string;
448
501
  }): DeepnoteFile;
502
+ /**
503
+ * Reads and converts multiple Jupyter Notebook (.ipynb) files into a DeepnoteFile.
504
+ * This function reads the files and returns the converted DeepnoteFile without writing to disk.
505
+ *
506
+ * @param inputFilePaths - Array of paths to .ipynb files
507
+ * @param options - Conversion options including project name
508
+ * @returns A DeepnoteFile object
509
+ */
510
+ declare function readAndConvertIpynbFiles(inputFilePaths: string[], options: ReadAndConvertIpynbFilesOptions): Promise<DeepnoteFile>;
449
511
  /**
450
512
  * Converts multiple Jupyter Notebook (.ipynb) files into a single Deepnote project file.
451
513
  */
@@ -456,9 +518,14 @@ interface ConvertMarimoFilesToDeepnoteFileOptions {
456
518
  outputPath: string;
457
519
  projectName: string;
458
520
  }
521
+ interface ReadAndConvertMarimoFilesOptions {
522
+ projectName: string;
523
+ }
459
524
  interface ConvertMarimoAppOptions {
460
525
  /** Custom ID generator function. Defaults to crypto.randomUUID(). */
461
526
  idGenerator?: () => string;
527
+ /** Outputs from Marimo session cache, keyed by code_hash */
528
+ outputs?: Map<string, JupyterOutput[]>;
462
529
  }
463
530
  interface MarimoAppInput {
464
531
  filename: string;
@@ -490,7 +557,7 @@ declare function parseMarimoFormat(content: string): MarimoApp;
490
557
  * This is the lowest-level conversion function.
491
558
  *
492
559
  * @param app - The Marimo app object to convert
493
- * @param options - Optional conversion options including custom ID generator
560
+ * @param options - Optional conversion options including custom ID generator and outputs
494
561
  * @returns Array of DeepnoteBlock objects
495
562
  */
496
563
  declare function convertMarimoAppToBlocks(app: MarimoApp, options?: ConvertMarimoAppOptions): DeepnoteBlock[];
@@ -509,6 +576,15 @@ interface ConvertMarimoAppsToDeepnoteOptions {
509
576
  * @returns A DeepnoteFile object
510
577
  */
511
578
  declare function convertMarimoAppsToDeepnote(apps: MarimoAppInput[], options: ConvertMarimoAppsToDeepnoteOptions): DeepnoteFile;
579
+ /**
580
+ * Reads and converts multiple Marimo (.py) files into a DeepnoteFile.
581
+ * This function reads the files and returns the converted DeepnoteFile without writing to disk.
582
+ *
583
+ * @param inputFilePaths - Array of paths to Marimo .py files
584
+ * @param options - Conversion options including project name
585
+ * @returns A DeepnoteFile object
586
+ */
587
+ declare function readAndConvertMarimoFiles(inputFilePaths: string[], options: ReadAndConvertMarimoFilesOptions): Promise<DeepnoteFile>;
512
588
  /**
513
589
  * Converts multiple Marimo (.py) files into a single Deepnote project file.
514
590
  */
@@ -519,6 +595,9 @@ interface ConvertPercentFilesToDeepnoteFileOptions {
519
595
  outputPath: string;
520
596
  projectName: string;
521
597
  }
598
+ interface ReadAndConvertPercentFilesOptions {
599
+ projectName: string;
600
+ }
522
601
  interface ConvertPercentNotebookOptions {
523
602
  /** Custom ID generator function. Defaults to crypto.randomUUID(). */
524
603
  idGenerator?: () => string;
@@ -565,6 +644,15 @@ declare function convertPercentNotebookToBlocks(notebook: PercentNotebook, optio
565
644
  declare function convertPercentNotebooksToDeepnote(notebooks: PercentNotebookInput[], options: {
566
645
  projectName: string;
567
646
  }): DeepnoteFile;
647
+ /**
648
+ * Reads and converts multiple percent format (.py) files into a DeepnoteFile.
649
+ * This function reads the files and returns the converted DeepnoteFile without writing to disk.
650
+ *
651
+ * @param inputFilePaths - Array of paths to percent format .py files
652
+ * @param options - Conversion options including project name
653
+ * @returns A DeepnoteFile object
654
+ */
655
+ declare function readAndConvertPercentFiles(inputFilePaths: string[], options: ReadAndConvertPercentFilesOptions): Promise<DeepnoteFile>;
568
656
  /**
569
657
  * Converts multiple percent format (.py) files into a single Deepnote project file.
570
658
  */
@@ -575,6 +663,9 @@ interface ConvertQuartoFilesToDeepnoteFileOptions {
575
663
  outputPath: string;
576
664
  projectName: string;
577
665
  }
666
+ interface ReadAndConvertQuartoFilesOptions {
667
+ projectName: string;
668
+ }
578
669
  interface ConvertQuartoDocumentOptions {
579
670
  /** Custom ID generator function. Defaults to crypto.randomUUID(). */
580
671
  idGenerator?: () => string;
@@ -625,9 +716,249 @@ declare function convertQuartoDocumentToBlocks(document: QuartoDocument, options
625
716
  declare function convertQuartoDocumentsToDeepnote(documents: QuartoDocumentInput[], options: {
626
717
  projectName: string;
627
718
  }): DeepnoteFile;
719
+ /**
720
+ * Reads and converts multiple Quarto (.qmd) files into a DeepnoteFile.
721
+ * This function reads the files and returns the converted DeepnoteFile without writing to disk.
722
+ *
723
+ * @param inputFilePaths - Array of paths to .qmd files
724
+ * @param options - Conversion options including project name
725
+ * @returns A DeepnoteFile object
726
+ */
727
+ declare function readAndConvertQuartoFiles(inputFilePaths: string[], options: ReadAndConvertQuartoFilesOptions): Promise<DeepnoteFile>;
628
728
  /**
629
729
  * Converts multiple Quarto (.qmd) files into a single Deepnote project file.
630
730
  */
631
731
  declare function convertQuartoFilesToDeepnoteFile(inputFilePaths: string[], options: ConvertQuartoFilesToDeepnoteFileOptions): Promise<void>;
632
732
  //#endregion
633
- export { type ConvertBlocksToJupyterOptions, type ConvertDeepnoteFileToMarimoOptions, type ConvertDeepnoteFileToPercentOptions, type ConvertDeepnoteFileToQuartoOptions, type ConvertIpynbFilesToDeepnoteFileOptions, type ConvertJupyterNotebookOptions, type ConvertMarimoAppOptions, type ConvertMarimoAppsToDeepnoteOptions, type ConvertMarimoFilesToDeepnoteFileOptions, type ConvertPercentFilesToDeepnoteFileOptions, type ConvertPercentNotebookOptions, type ConvertQuartoDocumentOptions, type ConvertQuartoFilesToDeepnoteFileOptions, type JupyterCell, type JupyterNotebook, type JupyterNotebookInput, type MarimoApp, type MarimoAppInput, type MarimoCell, type NotebookFormat, type PercentCell, type PercentNotebook, type PercentNotebookInput, type QuartoCell, type QuartoCellOptions, type QuartoDocument, type QuartoDocumentInput, type QuartoFrontmatter, convertBlocksToJupyterNotebook, convertBlocksToMarimoApp, convertBlocksToPercentNotebook, convertBlocksToQuartoDocument, convertDeepnoteFileToJupyterFiles as convertDeepnoteFileToJupyter, convertDeepnoteFileToMarimoFiles, convertDeepnoteFileToPercentFiles, convertDeepnoteFileToQuartoFiles, convertDeepnoteToJupyterNotebooks, convertDeepnoteToMarimoApps, convertDeepnoteToPercentNotebooks, convertDeepnoteToQuartoDocuments, convertIpynbFilesToDeepnoteFile, convertJupyterNotebookToBlocks, convertJupyterNotebooksToDeepnote, convertMarimoAppToBlocks, convertMarimoAppsToDeepnote, convertMarimoFilesToDeepnoteFile, convertPercentFilesToDeepnoteFile, convertPercentNotebookToBlocks, convertPercentNotebooksToDeepnote, convertQuartoDocumentToBlocks, convertQuartoDocumentsToDeepnote, convertQuartoFilesToDeepnoteFile, detectFormat, parseMarimoFormat, parsePercentFormat, parseQuartoFormat, serializeMarimoFormat, serializePercentFormat, serializeQuartoFormat };
733
+ //#region src/snapshot/hash.d.ts
734
+ /**
735
+ * Computes a SHA-256 hash of the given content.
736
+ *
737
+ * @param content - The content to hash
738
+ * @returns Hash string in format 'sha256:{hex}'
739
+ */
740
+ declare function computeContentHash(content: string): string;
741
+ /**
742
+ * Computes a snapshot hash from the file's key properties.
743
+ * The hash is based on: version, environment.hash, integrations, and all block contentHashes.
744
+ *
745
+ * @param file - The DeepnoteFile to compute hash for
746
+ * @returns Hash string in format 'sha256:{hex}'
747
+ */
748
+ declare function computeSnapshotHash(file: DeepnoteFile): string;
749
+ /**
750
+ * Adds content hashes to all blocks in a DeepnoteFile that don't already have them.
751
+ * Returns a new DeepnoteFile with hashes added (does not mutate the input).
752
+ *
753
+ * @param file - The DeepnoteFile to add hashes to
754
+ * @returns A new DeepnoteFile with content hashes added
755
+ */
756
+ declare function addContentHashes(file: DeepnoteFile): DeepnoteFile;
757
+ //#endregion
758
+ //#region src/snapshot/types.d.ts
759
+ /**
760
+ * Options for snapshot operations
761
+ */
762
+ interface SnapshotOptions {
763
+ /** Directory where snapshot files are stored (default: 'snapshots') */
764
+ snapshotDir?: string;
765
+ }
766
+ /**
767
+ * Result of splitting a DeepnoteFile into source and snapshot
768
+ */
769
+ interface SplitResult {
770
+ /** The source file without outputs */
771
+ source: DeepnoteFile;
772
+ /** The snapshot file containing outputs */
773
+ snapshot: DeepnoteSnapshot;
774
+ }
775
+ /**
776
+ * Block output information stored in a snapshot
777
+ */
778
+ interface BlockOutput {
779
+ /** Block ID */
780
+ id: string;
781
+ /** Content hash of the source when output was generated */
782
+ contentHash?: string;
783
+ /** Execution count */
784
+ executionCount?: number | null;
785
+ /** When execution started */
786
+ executionStartedAt?: string;
787
+ /** When execution finished */
788
+ executionFinishedAt?: string;
789
+ /** Output data */
790
+ outputs?: unknown[];
791
+ }
792
+ /**
793
+ * Information about a snapshot file
794
+ */
795
+ interface SnapshotInfo {
796
+ /** Full path to the snapshot file */
797
+ path: string;
798
+ /** Project name slug */
799
+ slug: string;
800
+ /** Project ID */
801
+ projectId: string;
802
+ /** Timestamp or 'latest' */
803
+ timestamp: string;
804
+ }
805
+ /**
806
+ * Options for merging a snapshot into a source file
807
+ */
808
+ interface MergeOptions {
809
+ /** Whether to skip blocks with mismatched content hashes (default: false) */
810
+ skipMismatched?: boolean;
811
+ }
812
+ //#endregion
813
+ //#region src/snapshot/lookup.d.ts
814
+ /**
815
+ * Parses a snapshot filename into its components.
816
+ *
817
+ * @param filename - The snapshot filename to parse
818
+ * @returns Parsed components or null if filename doesn't match pattern
819
+ */
820
+ declare function parseSnapshotFilename(filename: string): {
821
+ slug: string;
822
+ projectId: string;
823
+ timestamp: string;
824
+ } | null;
825
+ /**
826
+ * Finds all snapshot files for a given project.
827
+ *
828
+ * @param projectDir - Directory containing the .deepnote file
829
+ * @param projectId - The project UUID to search for
830
+ * @param options - Snapshot options
831
+ * @returns Array of SnapshotInfo objects, sorted by timestamp (newest first)
832
+ */
833
+ declare function findSnapshotsForProject(projectDir: string, projectId: string, options?: SnapshotOptions): Promise<SnapshotInfo[]>;
834
+ /**
835
+ * Loads the latest snapshot for a project.
836
+ *
837
+ * @param sourceFilePath - Path to the source .deepnote file
838
+ * @param projectId - The project UUID
839
+ * @param options - Snapshot options
840
+ * @returns The parsed DeepnoteSnapshot or null if not found
841
+ */
842
+ declare function loadLatestSnapshot(sourceFilePath: string, projectId: string, options?: SnapshotOptions): Promise<DeepnoteSnapshot | null>;
843
+ /**
844
+ * Loads and parses a snapshot file.
845
+ *
846
+ * @param snapshotPath - Path to the snapshot file
847
+ * @returns The parsed DeepnoteSnapshot
848
+ */
849
+ declare function loadSnapshotFile(snapshotPath: string): Promise<DeepnoteSnapshot>;
850
+ /**
851
+ * Gets the snapshot directory path for a source file.
852
+ *
853
+ * @param sourceFilePath - Path to the source .deepnote file
854
+ * @param options - Snapshot options
855
+ * @returns The snapshot directory path
856
+ */
857
+ declare function getSnapshotDir(sourceFilePath: string, options?: SnapshotOptions): string;
858
+ /**
859
+ * Checks if a snapshot exists for a project.
860
+ *
861
+ * @param sourceFilePath - Path to the source .deepnote file
862
+ * @param projectId - The project UUID
863
+ * @param options - Snapshot options
864
+ * @returns True if at least one snapshot exists
865
+ */
866
+ declare function snapshotExists(sourceFilePath: string, projectId: string, options?: SnapshotOptions): Promise<boolean>;
867
+ /**
868
+ * Extracts project information from a source file path.
869
+ *
870
+ * @param sourceFilePath - Path to the source .deepnote file
871
+ * @returns Object with directory and filename without extension
872
+ */
873
+ declare function parseSourceFilePath(sourceFilePath: string): {
874
+ dir: string;
875
+ name: string;
876
+ };
877
+ //#endregion
878
+ //#region src/snapshot/merge.d.ts
879
+ /**
880
+ * Merges outputs from a snapshot into a source file.
881
+ * Returns a new DeepnoteFile with outputs added from the snapshot.
882
+ *
883
+ * @param source - The source DeepnoteFile (without outputs)
884
+ * @param snapshot - The snapshot containing outputs
885
+ * @param options - Merge options
886
+ * @returns A new DeepnoteFile with outputs merged in
887
+ */
888
+ declare function mergeSnapshotIntoSource(source: DeepnoteFile, snapshot: DeepnoteSnapshot, options?: MergeOptions): DeepnoteFile;
889
+ /**
890
+ * Counts blocks with outputs in a file.
891
+ *
892
+ * @param file - The DeepnoteFile to count outputs in
893
+ * @returns Number of blocks that have outputs
894
+ */
895
+ declare function countBlocksWithOutputs(file: DeepnoteFile): number;
896
+ //#endregion
897
+ //#region src/snapshot/split.d.ts
898
+ /**
899
+ * Creates a slug from a project name.
900
+ * Normalizes accented characters to ASCII equivalents (e.g., é → e),
901
+ * converts to lowercase, replaces spaces and special chars with hyphens,
902
+ * removes consecutive hyphens, and trims leading/trailing hyphens.
903
+ *
904
+ * @param name - The project name to slugify
905
+ * @returns A URL-safe slug
906
+ */
907
+ declare function slugifyProjectName(name: string): string;
908
+ /**
909
+ * Generates a snapshot filename from project info.
910
+ *
911
+ * @param slug - The project name slug
912
+ * @param projectId - The project UUID
913
+ * @param timestamp - Timestamp string or 'latest'
914
+ * @returns Filename in format '{slug}_{projectId}_{timestamp}.snapshot.deepnote'
915
+ */
916
+ declare function generateSnapshotFilename(slug: string, projectId: string, timestamp?: string): string;
917
+ /**
918
+ * Splits a DeepnoteFile into a source file (no outputs) and a snapshot file (outputs only).
919
+ *
920
+ * @param file - The complete DeepnoteFile with outputs
921
+ * @returns Object containing source and snapshot files
922
+ */
923
+ declare function splitDeepnoteFile(file: DeepnoteFile): SplitResult;
924
+ /**
925
+ * Checks if a DeepnoteFile has any outputs.
926
+ *
927
+ * @param file - The DeepnoteFile to check
928
+ * @returns True if any block has outputs
929
+ */
930
+ declare function hasOutputs(file: DeepnoteFile): boolean;
931
+ //#endregion
932
+ //#region src/write-deepnote-file.d.ts
933
+ interface WriteDeepnoteFileOptions {
934
+ /** The DeepnoteFile to write */
935
+ file: DeepnoteFile;
936
+ /** Path where the main .deepnote file should be written */
937
+ outputPath: string;
938
+ /** Project name used for snapshot filename */
939
+ projectName: string;
940
+ /** When true, outputs are included in the main file (disables snapshot mode) */
941
+ singleFile?: boolean;
942
+ }
943
+ interface WriteDeepnoteFileResult {
944
+ /** Path to the written source file */
945
+ sourcePath: string;
946
+ /** Path to the snapshot file (only if outputs were split) */
947
+ snapshotPath?: string;
948
+ }
949
+ /**
950
+ * Writes a DeepnoteFile to disk, optionally splitting outputs into a snapshot file.
951
+ *
952
+ * When singleFile is false (default) and the file contains outputs:
953
+ * - Splits the file in memory into source (no outputs) and snapshot (with outputs)
954
+ * - Writes both files in parallel
955
+ *
956
+ * When singleFile is true or there are no outputs:
957
+ * - Writes the complete file as-is
958
+ *
959
+ * @param options - Write options including the file, output path, and project name
960
+ * @returns Object containing paths to the written files
961
+ */
962
+ declare function writeDeepnoteFile(options: WriteDeepnoteFileOptions): Promise<WriteDeepnoteFileResult>;
963
+ //#endregion
964
+ export { type BlockOutput, type ConvertBlocksToJupyterOptions, type ConvertDeepnoteFileToMarimoOptions, type ConvertDeepnoteFileToPercentOptions, type ConvertDeepnoteFileToQuartoOptions, type ConvertIpynbFilesToDeepnoteFileOptions, type ConvertJupyterNotebookOptions, type ConvertMarimoAppOptions, type ConvertMarimoAppsToDeepnoteOptions, type ConvertMarimoFilesToDeepnoteFileOptions, type ConvertPercentFilesToDeepnoteFileOptions, type ConvertPercentNotebookOptions, type ConvertQuartoDocumentOptions, type ConvertQuartoFilesToDeepnoteFileOptions, type JupyterCell, type JupyterNotebook, type JupyterNotebookInput, type MarimoApp, type MarimoAppInput, type MarimoCell, type MergeOptions, type NotebookFormat, type PercentCell, type PercentNotebook, type PercentNotebookInput, type QuartoCell, type QuartoCellOptions, type QuartoDocument, type QuartoDocumentInput, type QuartoFrontmatter, type ReadAndConvertIpynbFilesOptions, type ReadAndConvertMarimoFilesOptions, type ReadAndConvertPercentFilesOptions, type ReadAndConvertQuartoFilesOptions, type SnapshotInfo, type SnapshotOptions, type SplitResult, type WriteDeepnoteFileOptions, type WriteDeepnoteFileResult, addContentHashes, computeContentHash, computeSnapshotHash, convertBlockToJupyterCell, convertBlocksToJupyterNotebook, convertBlocksToMarimoApp, convertBlocksToPercentNotebook, convertBlocksToQuartoDocument, convertDeepnoteFileToJupyterFiles, convertDeepnoteFileToMarimoFiles, convertDeepnoteFileToPercentFiles, convertDeepnoteFileToQuartoFiles, convertDeepnoteToJupyterNotebooks, convertDeepnoteToMarimoApps, convertDeepnoteToPercentNotebooks, convertDeepnoteToQuartoDocuments, convertIpynbFilesToDeepnoteFile, convertJupyterNotebookToBlocks, convertJupyterNotebooksToDeepnote, convertMarimoAppToBlocks, convertMarimoAppsToDeepnote, convertMarimoFilesToDeepnoteFile, convertPercentFilesToDeepnoteFile, convertPercentNotebookToBlocks, convertPercentNotebooksToDeepnote, convertQuartoDocumentToBlocks, convertQuartoDocumentsToDeepnote, convertQuartoFilesToDeepnoteFile, countBlocksWithOutputs, detectFormat, findSnapshotsForProject, generateSnapshotFilename, getSnapshotDir, hasOutputs, loadLatestSnapshot, loadSnapshotFile, mergeSnapshotIntoSource, parseMarimoFormat, parsePercentFormat, parseQuartoFormat, parseSnapshotFilename, parseSourceFilePath, readAndConvertIpynbFiles, readAndConvertMarimoFiles, readAndConvertPercentFiles, readAndConvertQuartoFiles, serializeMarimoFormat, serializePercentFormat, serializeQuartoFormat, slugifyProjectName, snapshotExists, splitDeepnoteFile, writeDeepnoteFile };