@deepnote/blocks 3.2.1 → 4.0.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.cjs CHANGED
@@ -28,23 +28,70 @@ yaml = __toESM(yaml);
28
28
  let ts_dedent = require("ts-dedent");
29
29
  ts_dedent = __toESM(ts_dedent);
30
30
 
31
- //#region src/blocks.ts
32
- var UnsupportedBlockTypeError = class extends Error {
33
- constructor(message) {
34
- super(message);
35
- this.name = "UnsupportedBlockTypeError";
31
+ //#region src/errors.ts
32
+ /**
33
+ * Base error class for all Deepnote errors.
34
+ */
35
+ var DeepnoteError = class extends Error {
36
+ constructor(message, options) {
37
+ super(message, options);
38
+ this.name = this.constructor.name;
39
+ }
40
+ };
41
+ /**
42
+ * Generic parse failure, optionally associated with a file path.
43
+ */
44
+ var ParseError = class extends DeepnoteError {
45
+ filePath;
46
+ constructor(message, options) {
47
+ super(message, options);
48
+ this.filePath = options?.filePath;
49
+ }
50
+ };
51
+ /**
52
+ * YAML syntax or duplicate key errors.
53
+ */
54
+ var YamlParseError = class extends ParseError {};
55
+ /**
56
+ * BOM or invalid UTF-8 encoding errors.
57
+ */
58
+ var EncodingError = class extends ParseError {};
59
+ /**
60
+ * Zod schema validation failures.
61
+ */
62
+ var SchemaValidationError = class extends ParseError {};
63
+ /**
64
+ * Prohibited YAML features: anchors, aliases, merge keys, tags.
65
+ */
66
+ var ProhibitedYamlFeatureError = class extends ParseError {
67
+ feature;
68
+ constructor(message, options) {
69
+ super(message, options);
70
+ this.feature = options.feature;
71
+ }
72
+ };
73
+ /**
74
+ * Thrown when a block type is not supported.
75
+ */
76
+ var UnsupportedBlockTypeError = class extends DeepnoteError {};
77
+ /**
78
+ * Thrown when a value is invalid (e.g., slider value, date interval).
79
+ */
80
+ var InvalidValueError = class extends DeepnoteError {
81
+ value;
82
+ constructor(message, options) {
83
+ super(message, options);
84
+ this.value = options.value;
36
85
  }
37
86
  };
38
87
 
39
88
  //#endregion
40
89
  //#region src/blocks/executable-blocks.ts
41
- const executableBlockTypes = new Set([
42
- "code",
43
- "sql",
44
- "notebook-function",
45
- "visualization",
46
- "button",
47
- "big-number",
90
+ /**
91
+ * Block types that represent user input widgets.
92
+ * These blocks capture user input and define variables.
93
+ */
94
+ const INPUT_BLOCK_TYPES = new Set([
48
95
  "input-text",
49
96
  "input-textarea",
50
97
  "input-checkbox",
@@ -54,6 +101,15 @@ const executableBlockTypes = new Set([
54
101
  "input-date-range",
55
102
  "input-file"
56
103
  ]);
104
+ const executableBlockTypes = new Set([
105
+ "code",
106
+ "sql",
107
+ "notebook-function",
108
+ "visualization",
109
+ "button",
110
+ "big-number",
111
+ ...INPUT_BLOCK_TYPES
112
+ ]);
57
113
  /**
58
114
  * Type guard to check if a block is an executable block.
59
115
  * Executable blocks can have outputs and be executed by the runtime.
@@ -69,6 +125,15 @@ function isExecutableBlockType(type) {
69
125
  return executableBlockTypes.has(type);
70
126
  }
71
127
 
128
+ //#endregion
129
+ //#region src/blocks/sql-utils.ts
130
+ function convertToEnvironmentVariableName(str) {
131
+ return (/^\d/.test(str) ? `_${str}` : str).toUpperCase().replace(/[^\w]/g, "_");
132
+ }
133
+ function getSqlEnvVarName(integrationId) {
134
+ return `SQL_${integrationId}`;
135
+ }
136
+
72
137
  //#endregion
73
138
  //#region src/deserialize-file/deepnote-file-schema.ts
74
139
  /** Preprocesses any content value to empty string for blocks that don't use content */
@@ -482,7 +547,7 @@ const deepnoteSnapshotSchema = deepnoteFileSchema.extend({
482
547
  *
483
548
  * @param bytes - Raw file bytes as Uint8Array
484
549
  * @returns Decoded UTF-8 string without BOM
485
- * @throws Error if BOM detected or invalid UTF-8 encoding
550
+ * @throws EncodingError if BOM detected or invalid UTF-8 encoding
486
551
  *
487
552
  * @example
488
553
  * ```typescript
@@ -492,11 +557,11 @@ const deepnoteSnapshotSchema = deepnoteFileSchema.extend({
492
557
  * ```
493
558
  */
494
559
  function decodeUtf8NoBom(bytes) {
495
- if (bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) throw new Error("UTF-8 BOM detected in Deepnote file - files must be UTF-8 without BOM");
560
+ if (bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) throw new EncodingError("UTF-8 BOM detected in Deepnote file - files must be UTF-8 without BOM");
496
561
  try {
497
562
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
498
563
  } catch {
499
- throw new Error("Invalid UTF-8 encoding detected in Deepnote file");
564
+ throw new EncodingError("Invalid UTF-8 encoding detected in Deepnote file");
500
565
  }
501
566
  }
502
567
  /**
@@ -506,10 +571,10 @@ function decodeUtf8NoBom(bytes) {
506
571
  * For proper UTF-8 validation, use decodeUtf8NoBom() on raw bytes before decoding.
507
572
  *
508
573
  * @param yamlContent - Already-decoded YAML string
509
- * @throws Error if BOM prefix detected
574
+ * @throws EncodingError if BOM prefix detected
510
575
  */
511
576
  function validateNoBomPrefix(yamlContent) {
512
- if (yamlContent.charCodeAt(0) === 65279) throw new Error("UTF-8 BOM detected in Deepnote file - files must be UTF-8 without BOM");
577
+ if (yamlContent.charCodeAt(0) === 65279) throw new EncodingError("UTF-8 BOM detected in Deepnote file - files must be UTF-8 without BOM");
513
578
  }
514
579
  /**
515
580
  * Validates that the YAML document doesn't contain prohibited features:
@@ -518,13 +583,13 @@ function validateNoBomPrefix(yamlContent) {
518
583
  * - No custom tags (!tag)
519
584
  */
520
585
  function validateYamlStructure(yamlContent) {
521
- if (/(?:^|\n)\s*(?:-\s+|[\w-]+:\s*)&\w+/.test(yamlContent)) throw new Error("YAML anchors (&) are not allowed in Deepnote files");
522
- if (/(?:^|\n)\s*(?:-\s+|[\w-]+:\s*)\*\w+/.test(yamlContent)) throw new Error("YAML aliases (*) are not allowed in Deepnote files");
523
- if (/<<:/.test(yamlContent)) throw new Error("YAML merge keys (<<) are not allowed in Deepnote files");
586
+ if (/(?:^|\n)\s*(?:-\s+|[\w-]+:\s*)&\w+/.test(yamlContent)) throw new ProhibitedYamlFeatureError("YAML anchors (&) are not allowed in Deepnote files", { feature: "anchor" });
587
+ if (/(?:^|\n)\s*(?:-\s+|[\w-]+:\s*)\*\w+/.test(yamlContent)) throw new ProhibitedYamlFeatureError("YAML aliases (*) are not allowed in Deepnote files", { feature: "alias" });
588
+ if (/<<:/.test(yamlContent)) throw new ProhibitedYamlFeatureError("YAML merge keys (<<) are not allowed in Deepnote files", { feature: "merge-key" });
524
589
  const matches = yamlContent.match(/(?:^|\n)\s*(?:-\s+|[\w-]+:\s*)(![\w/-]+)/gm);
525
590
  if (matches) {
526
591
  const tags = matches.map((m) => m.match(/(![\w/-]+)/)?.[1]).filter(Boolean);
527
- if (tags.length > 0) throw new Error(`YAML tags are not allowed in Deepnote files: ${tags.join(", ")}`);
592
+ if (tags.length > 0) throw new ProhibitedYamlFeatureError(`YAML tags are not allowed in Deepnote files: ${tags.join(", ")}`, { feature: "tag" });
528
593
  }
529
594
  }
530
595
  /**
@@ -539,8 +604,8 @@ function parseAndValidate(yamlContent) {
539
604
  });
540
605
  if (doc.errors.length > 0) {
541
606
  const duplicateKeyError = doc.errors.find((err) => err.message.includes("duplicate") || err.message.includes("key"));
542
- if (duplicateKeyError) throw new Error(`Duplicate keys detected in Deepnote file: ${duplicateKeyError.message}`);
543
- throw new Error(`YAML parsing error: ${doc.errors[0].message}`);
607
+ if (duplicateKeyError) throw new YamlParseError(`Duplicate keys detected in Deepnote file: ${duplicateKeyError.message}`);
608
+ throw new YamlParseError(`YAML parsing error: ${doc.errors[0].message}`);
544
609
  }
545
610
  return doc.toJS();
546
611
  }
@@ -559,8 +624,8 @@ function parseYaml(yamlContent) {
559
624
  validateYamlStructure(yamlContent);
560
625
  return parseAndValidate(yamlContent);
561
626
  } catch (error) {
562
- const message = error instanceof Error ? error.message : String(error);
563
- throw new Error(`Failed to parse Deepnote file: ${message}`);
627
+ if (error instanceof DeepnoteError) throw error;
628
+ throw new ParseError(`Failed to parse Deepnote file: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
564
629
  }
565
630
  }
566
631
 
@@ -574,10 +639,9 @@ function deserializeDeepnoteFile(yamlContent) {
574
639
  const result = deepnoteFileSchema.safeParse(parsed);
575
640
  if (!result.success) {
576
641
  const issue = result.error.issues[0];
577
- if (!issue) throw new Error("Invalid Deepnote file.");
642
+ if (!issue) throw new SchemaValidationError("Invalid Deepnote file.");
578
643
  const path = issue.path.join(".");
579
- const message = path ? `${path}: ${issue.message}` : issue.message;
580
- throw new Error(`Failed to parse the Deepnote file: ${message}.`);
644
+ throw new SchemaValidationError(`Failed to parse the Deepnote file: ${path ? `${path}: ${issue.message}` : issue.message}.`);
581
645
  }
582
646
  return result.data;
583
647
  }
@@ -629,7 +693,7 @@ function createMarkdownForTextBlock(block) {
629
693
  if (block.type === "text-cell-todo") return `- ${block.metadata?.checked ? "[x]" : "[ ]"} ${escapeMarkdown(content)}`;
630
694
  if (block.type === "text-cell-callout") return `> ${escapeMarkdown(content)}`;
631
695
  if (block.type === "text-cell-p") return escapeMarkdown(content);
632
- throw new Error("Unhandled block type.");
696
+ throw new UnsupportedBlockTypeError("Unhandled block type.");
633
697
  }
634
698
  function stripMarkdownFromTextBlock(block) {
635
699
  const content = block.content ?? "";
@@ -640,7 +704,7 @@ function stripMarkdownFromTextBlock(block) {
640
704
  if (block.type === "text-cell-todo") return content.replace(/^-+\s+\[.\]\s+/, "").trim();
641
705
  if (block.type === "text-cell-callout") return content.replace(/^>\s+/, "").trim();
642
706
  if (block.type === "text-cell-p") return content.trim();
643
- throw new Error("Unhandled block type.");
707
+ throw new UnsupportedBlockTypeError("Unhandled block type.");
644
708
  }
645
709
  function createMarkdownForSeparatorBlock(_block) {
646
710
  return "<hr>";
@@ -914,9 +978,9 @@ function createPythonCodeForInputSelectBlock(block) {
914
978
  function createPythonCodeForInputSliderBlock(block) {
915
979
  const sanitizedPythonVariableName = sanitizePythonVariableName(block.metadata.deepnote_variable_name);
916
980
  const value = block.metadata.deepnote_variable_value;
917
- if (!/^-?\d+\.?\d*$|^-?\d*\.\d+$/.test(value)) throw new Error(`Invalid numeric value for slider input: "${value}". Expected a valid number (integer or float).`);
981
+ if (!/^-?\d+\.?\d*$|^-?\d*\.\d+$/.test(value)) throw new InvalidValueError(`Invalid numeric value for slider input: "${value}". Expected a valid number (integer or float).`, { value });
918
982
  const numericValue = Number(value);
919
- if (!Number.isFinite(numericValue)) throw new Error(`Invalid numeric value for slider input: "${value}". Value must be finite.`);
983
+ if (!Number.isFinite(numericValue)) throw new InvalidValueError(`Invalid numeric value for slider input: "${value}". Value must be finite.`, { value });
920
984
  return `${sanitizedPythonVariableName} = ${numericValue}`;
921
985
  }
922
986
  function createPythonCodeForInputFileBlock(block) {
@@ -950,7 +1014,7 @@ function createPythonCodeForInputDateRangeBlock(block) {
950
1014
  return pythonCode.dateRangeCustomDays(sanitizedPythonVariableName, Number(customDays));
951
1015
  } else if (isValidRelativeDateInterval(block.metadata.deepnote_variable_value)) {
952
1016
  const range = DATE_RANGE_INPUT_RELATIVE_RANGES.find((range$1) => range$1.value === block.metadata.deepnote_variable_value);
953
- if (!range) throw new Error(`Invalid relative date interval: "${block.metadata.deepnote_variable_value}". Expected one of: ${DATE_RANGE_INPUT_RELATIVE_RANGES.map((r) => r.value).join(", ")}.`);
1017
+ if (!range) throw new InvalidValueError(`Invalid relative date interval: "${block.metadata.deepnote_variable_value}". Expected one of: ${DATE_RANGE_INPUT_RELATIVE_RANGES.map((r) => r.value).join(", ")}.`, { value: block.metadata.deepnote_variable_value });
954
1018
  return ts_dedent.dedent`
955
1019
  ${range.pythonCode(sanitizedPythonVariableName)}`;
956
1020
  } else return ts_dedent.dedent`
@@ -1029,15 +1093,6 @@ function createPythonCodeForNotebookFunctionBlock(block) {
1029
1093
  `;
1030
1094
  }
1031
1095
 
1032
- //#endregion
1033
- //#region src/blocks/sql-utils.ts
1034
- function convertToEnvironmentVariableName(str) {
1035
- return (/^\d/.test(str) ? `_${str}` : str).toUpperCase().replace(/[^\w]/g, "_");
1036
- }
1037
- function getSqlEnvVarName(integrationId) {
1038
- return `SQL_${integrationId}`;
1039
- }
1040
-
1041
1096
  //#endregion
1042
1097
  //#region src/blocks/sql-blocks.ts
1043
1098
  function createPythonCodeForSqlBlock(block) {
@@ -1109,7 +1164,16 @@ function createPythonCode(block, executionContext) {
1109
1164
  }
1110
1165
 
1111
1166
  //#endregion
1167
+ exports.DeepnoteError = DeepnoteError;
1168
+ exports.EncodingError = EncodingError;
1169
+ exports.INPUT_BLOCK_TYPES = INPUT_BLOCK_TYPES;
1170
+ exports.InvalidValueError = InvalidValueError;
1171
+ exports.ParseError = ParseError;
1172
+ exports.ProhibitedYamlFeatureError = ProhibitedYamlFeatureError;
1173
+ exports.SchemaValidationError = SchemaValidationError;
1112
1174
  exports.UnsupportedBlockTypeError = UnsupportedBlockTypeError;
1175
+ exports.YamlParseError = YamlParseError;
1176
+ exports.convertToEnvironmentVariableName = convertToEnvironmentVariableName;
1113
1177
  exports.createMarkdown = createMarkdown;
1114
1178
  exports.createPythonCode = createPythonCode;
1115
1179
  exports.decodeUtf8NoBom = decodeUtf8NoBom;
@@ -1121,6 +1185,7 @@ exports.environmentSchema = environmentSchema;
1121
1185
  exports.executionErrorSchema = executionErrorSchema;
1122
1186
  exports.executionSchema = executionSchema;
1123
1187
  exports.executionSummarySchema = executionSummarySchema;
1188
+ exports.getSqlEnvVarName = getSqlEnvVarName;
1124
1189
  exports.isExecutableBlock = isExecutableBlock;
1125
1190
  exports.isExecutableBlockType = isExecutableBlockType;
1126
1191
  exports.parseYaml = parseYaml;
package/dist/index.d.cts CHANGED
@@ -1,8 +1,55 @@
1
1
  import { z } from "zod";
2
2
 
3
- //#region src/blocks.d.ts
4
- declare class UnsupportedBlockTypeError extends Error {
5
- constructor(message: string);
3
+ //#region src/errors.d.ts
4
+ /**
5
+ * Base error class for all Deepnote errors.
6
+ */
7
+ declare class DeepnoteError extends Error {
8
+ constructor(message: string, options?: ErrorOptions);
9
+ }
10
+ /**
11
+ * Generic parse failure, optionally associated with a file path.
12
+ */
13
+ declare class ParseError extends DeepnoteError {
14
+ filePath?: string;
15
+ constructor(message: string, options?: ErrorOptions & {
16
+ filePath?: string;
17
+ });
18
+ }
19
+ /**
20
+ * YAML syntax or duplicate key errors.
21
+ */
22
+ declare class YamlParseError extends ParseError {}
23
+ /**
24
+ * BOM or invalid UTF-8 encoding errors.
25
+ */
26
+ declare class EncodingError extends ParseError {}
27
+ /**
28
+ * Zod schema validation failures.
29
+ */
30
+ declare class SchemaValidationError extends ParseError {}
31
+ /**
32
+ * Prohibited YAML features: anchors, aliases, merge keys, tags.
33
+ */
34
+ declare class ProhibitedYamlFeatureError extends ParseError {
35
+ feature: string;
36
+ constructor(message: string, options: ErrorOptions & {
37
+ feature: string;
38
+ filePath?: string;
39
+ });
40
+ }
41
+ /**
42
+ * Thrown when a block type is not supported.
43
+ */
44
+ declare class UnsupportedBlockTypeError extends DeepnoteError {}
45
+ /**
46
+ * Thrown when a value is invalid (e.g., slider value, date interval).
47
+ */
48
+ declare class InvalidValueError extends DeepnoteError {
49
+ value: unknown;
50
+ constructor(message: string, options: ErrorOptions & {
51
+ value: unknown;
52
+ });
6
53
  }
7
54
  //#endregion
8
55
  //#region src/deserialize-file/deepnote-file-schema.d.ts
@@ -23417,6 +23464,11 @@ declare const deepnoteSnapshotSchema: z.ZodObject<{
23417
23464
  type DeepnoteSnapshot = z.infer<typeof deepnoteSnapshotSchema>;
23418
23465
  //#endregion
23419
23466
  //#region src/blocks/executable-blocks.d.ts
23467
+ /**
23468
+ * Block types that represent user input widgets.
23469
+ * These blocks capture user input and define variables.
23470
+ */
23471
+ declare const INPUT_BLOCK_TYPES: Set<string>;
23420
23472
  /**
23421
23473
  * Type guard to check if a block is an executable block.
23422
23474
  * Executable blocks can have outputs and be executed by the runtime.
@@ -23428,6 +23480,10 @@ declare function isExecutableBlock(block: DeepnoteBlock): block is ExecutableBlo
23428
23480
  */
23429
23481
  declare function isExecutableBlockType(type: string): boolean;
23430
23482
  //#endregion
23483
+ //#region src/blocks/sql-utils.d.ts
23484
+ declare function convertToEnvironmentVariableName(str: string): string;
23485
+ declare function getSqlEnvVarName(integrationId: string): string;
23486
+ //#endregion
23431
23487
  //#region src/blocks/table-state.d.ts
23432
23488
  interface TableState {
23433
23489
  cellFormattingRules?: {
@@ -23467,7 +23523,7 @@ declare function deserializeDeepnoteFile(yamlContent: string): DeepnoteFile;
23467
23523
  *
23468
23524
  * @param bytes - Raw file bytes as Uint8Array
23469
23525
  * @returns Decoded UTF-8 string without BOM
23470
- * @throws Error if BOM detected or invalid UTF-8 encoding
23526
+ * @throws EncodingError if BOM detected or invalid UTF-8 encoding
23471
23527
  *
23472
23528
  * @example
23473
23529
  * ```typescript
@@ -23504,4 +23560,4 @@ interface ButtonExecutionContext {
23504
23560
  //#region src/python-code.d.ts
23505
23561
  declare function createPythonCode(block: DeepnoteBlock, executionContext?: ButtonExecutionContext): string;
23506
23562
  //#endregion
23507
- export { type DeepnoteBlock, type DeepnoteFile, type DeepnoteSnapshot, type Environment, type ExecutableBlock, type Execution, type ExecutionError, type ExecutionSummary, type TableState, UnsupportedBlockTypeError, createMarkdown, createPythonCode, decodeUtf8NoBom, deepnoteBlockSchema, deepnoteFileSchema, deepnoteSnapshotSchema, deserializeDeepnoteFile, environmentSchema, executionErrorSchema, executionSchema, executionSummarySchema, isExecutableBlock, isExecutableBlockType, parseYaml, stripMarkdown };
23563
+ export { type DeepnoteBlock, DeepnoteError, type DeepnoteFile, type DeepnoteSnapshot, EncodingError, type Environment, type ExecutableBlock, type Execution, type ExecutionError, type ExecutionSummary, INPUT_BLOCK_TYPES, InvalidValueError, ParseError, ProhibitedYamlFeatureError, SchemaValidationError, type TableState, UnsupportedBlockTypeError, YamlParseError, convertToEnvironmentVariableName, createMarkdown, createPythonCode, decodeUtf8NoBom, deepnoteBlockSchema, deepnoteFileSchema, deepnoteSnapshotSchema, deserializeDeepnoteFile, environmentSchema, executionErrorSchema, executionSchema, executionSummarySchema, getSqlEnvVarName, isExecutableBlock, isExecutableBlockType, parseYaml, stripMarkdown };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,55 @@
1
1
  import { z } from "zod";
2
2
 
3
- //#region src/blocks.d.ts
4
- declare class UnsupportedBlockTypeError extends Error {
5
- constructor(message: string);
3
+ //#region src/errors.d.ts
4
+ /**
5
+ * Base error class for all Deepnote errors.
6
+ */
7
+ declare class DeepnoteError extends Error {
8
+ constructor(message: string, options?: ErrorOptions);
9
+ }
10
+ /**
11
+ * Generic parse failure, optionally associated with a file path.
12
+ */
13
+ declare class ParseError extends DeepnoteError {
14
+ filePath?: string;
15
+ constructor(message: string, options?: ErrorOptions & {
16
+ filePath?: string;
17
+ });
18
+ }
19
+ /**
20
+ * YAML syntax or duplicate key errors.
21
+ */
22
+ declare class YamlParseError extends ParseError {}
23
+ /**
24
+ * BOM or invalid UTF-8 encoding errors.
25
+ */
26
+ declare class EncodingError extends ParseError {}
27
+ /**
28
+ * Zod schema validation failures.
29
+ */
30
+ declare class SchemaValidationError extends ParseError {}
31
+ /**
32
+ * Prohibited YAML features: anchors, aliases, merge keys, tags.
33
+ */
34
+ declare class ProhibitedYamlFeatureError extends ParseError {
35
+ feature: string;
36
+ constructor(message: string, options: ErrorOptions & {
37
+ feature: string;
38
+ filePath?: string;
39
+ });
40
+ }
41
+ /**
42
+ * Thrown when a block type is not supported.
43
+ */
44
+ declare class UnsupportedBlockTypeError extends DeepnoteError {}
45
+ /**
46
+ * Thrown when a value is invalid (e.g., slider value, date interval).
47
+ */
48
+ declare class InvalidValueError extends DeepnoteError {
49
+ value: unknown;
50
+ constructor(message: string, options: ErrorOptions & {
51
+ value: unknown;
52
+ });
6
53
  }
7
54
  //#endregion
8
55
  //#region src/deserialize-file/deepnote-file-schema.d.ts
@@ -23417,6 +23464,11 @@ declare const deepnoteSnapshotSchema: z.ZodObject<{
23417
23464
  type DeepnoteSnapshot = z.infer<typeof deepnoteSnapshotSchema>;
23418
23465
  //#endregion
23419
23466
  //#region src/blocks/executable-blocks.d.ts
23467
+ /**
23468
+ * Block types that represent user input widgets.
23469
+ * These blocks capture user input and define variables.
23470
+ */
23471
+ declare const INPUT_BLOCK_TYPES: Set<string>;
23420
23472
  /**
23421
23473
  * Type guard to check if a block is an executable block.
23422
23474
  * Executable blocks can have outputs and be executed by the runtime.
@@ -23428,6 +23480,10 @@ declare function isExecutableBlock(block: DeepnoteBlock): block is ExecutableBlo
23428
23480
  */
23429
23481
  declare function isExecutableBlockType(type: string): boolean;
23430
23482
  //#endregion
23483
+ //#region src/blocks/sql-utils.d.ts
23484
+ declare function convertToEnvironmentVariableName(str: string): string;
23485
+ declare function getSqlEnvVarName(integrationId: string): string;
23486
+ //#endregion
23431
23487
  //#region src/blocks/table-state.d.ts
23432
23488
  interface TableState {
23433
23489
  cellFormattingRules?: {
@@ -23467,7 +23523,7 @@ declare function deserializeDeepnoteFile(yamlContent: string): DeepnoteFile;
23467
23523
  *
23468
23524
  * @param bytes - Raw file bytes as Uint8Array
23469
23525
  * @returns Decoded UTF-8 string without BOM
23470
- * @throws Error if BOM detected or invalid UTF-8 encoding
23526
+ * @throws EncodingError if BOM detected or invalid UTF-8 encoding
23471
23527
  *
23472
23528
  * @example
23473
23529
  * ```typescript
@@ -23504,4 +23560,4 @@ interface ButtonExecutionContext {
23504
23560
  //#region src/python-code.d.ts
23505
23561
  declare function createPythonCode(block: DeepnoteBlock, executionContext?: ButtonExecutionContext): string;
23506
23562
  //#endregion
23507
- export { type DeepnoteBlock, type DeepnoteFile, type DeepnoteSnapshot, type Environment, type ExecutableBlock, type Execution, type ExecutionError, type ExecutionSummary, type TableState, UnsupportedBlockTypeError, createMarkdown, createPythonCode, decodeUtf8NoBom, deepnoteBlockSchema, deepnoteFileSchema, deepnoteSnapshotSchema, deserializeDeepnoteFile, environmentSchema, executionErrorSchema, executionSchema, executionSummarySchema, isExecutableBlock, isExecutableBlockType, parseYaml, stripMarkdown };
23563
+ export { type DeepnoteBlock, DeepnoteError, type DeepnoteFile, type DeepnoteSnapshot, EncodingError, type Environment, type ExecutableBlock, type Execution, type ExecutionError, type ExecutionSummary, INPUT_BLOCK_TYPES, InvalidValueError, ParseError, ProhibitedYamlFeatureError, SchemaValidationError, type TableState, UnsupportedBlockTypeError, YamlParseError, convertToEnvironmentVariableName, createMarkdown, createPythonCode, decodeUtf8NoBom, deepnoteBlockSchema, deepnoteFileSchema, deepnoteSnapshotSchema, deserializeDeepnoteFile, environmentSchema, executionErrorSchema, executionSchema, executionSummarySchema, getSqlEnvVarName, isExecutableBlock, isExecutableBlockType, parseYaml, stripMarkdown };
package/dist/index.js CHANGED
@@ -2,23 +2,70 @@ import { z } from "zod";
2
2
  import { parseDocument } from "yaml";
3
3
  import { dedent } from "ts-dedent";
4
4
 
5
- //#region src/blocks.ts
6
- var UnsupportedBlockTypeError = class extends Error {
7
- constructor(message) {
8
- super(message);
9
- this.name = "UnsupportedBlockTypeError";
5
+ //#region src/errors.ts
6
+ /**
7
+ * Base error class for all Deepnote errors.
8
+ */
9
+ var DeepnoteError = class extends Error {
10
+ constructor(message, options) {
11
+ super(message, options);
12
+ this.name = this.constructor.name;
13
+ }
14
+ };
15
+ /**
16
+ * Generic parse failure, optionally associated with a file path.
17
+ */
18
+ var ParseError = class extends DeepnoteError {
19
+ filePath;
20
+ constructor(message, options) {
21
+ super(message, options);
22
+ this.filePath = options?.filePath;
23
+ }
24
+ };
25
+ /**
26
+ * YAML syntax or duplicate key errors.
27
+ */
28
+ var YamlParseError = class extends ParseError {};
29
+ /**
30
+ * BOM or invalid UTF-8 encoding errors.
31
+ */
32
+ var EncodingError = class extends ParseError {};
33
+ /**
34
+ * Zod schema validation failures.
35
+ */
36
+ var SchemaValidationError = class extends ParseError {};
37
+ /**
38
+ * Prohibited YAML features: anchors, aliases, merge keys, tags.
39
+ */
40
+ var ProhibitedYamlFeatureError = class extends ParseError {
41
+ feature;
42
+ constructor(message, options) {
43
+ super(message, options);
44
+ this.feature = options.feature;
45
+ }
46
+ };
47
+ /**
48
+ * Thrown when a block type is not supported.
49
+ */
50
+ var UnsupportedBlockTypeError = class extends DeepnoteError {};
51
+ /**
52
+ * Thrown when a value is invalid (e.g., slider value, date interval).
53
+ */
54
+ var InvalidValueError = class extends DeepnoteError {
55
+ value;
56
+ constructor(message, options) {
57
+ super(message, options);
58
+ this.value = options.value;
10
59
  }
11
60
  };
12
61
 
13
62
  //#endregion
14
63
  //#region src/blocks/executable-blocks.ts
15
- const executableBlockTypes = new Set([
16
- "code",
17
- "sql",
18
- "notebook-function",
19
- "visualization",
20
- "button",
21
- "big-number",
64
+ /**
65
+ * Block types that represent user input widgets.
66
+ * These blocks capture user input and define variables.
67
+ */
68
+ const INPUT_BLOCK_TYPES = new Set([
22
69
  "input-text",
23
70
  "input-textarea",
24
71
  "input-checkbox",
@@ -28,6 +75,15 @@ const executableBlockTypes = new Set([
28
75
  "input-date-range",
29
76
  "input-file"
30
77
  ]);
78
+ const executableBlockTypes = new Set([
79
+ "code",
80
+ "sql",
81
+ "notebook-function",
82
+ "visualization",
83
+ "button",
84
+ "big-number",
85
+ ...INPUT_BLOCK_TYPES
86
+ ]);
31
87
  /**
32
88
  * Type guard to check if a block is an executable block.
33
89
  * Executable blocks can have outputs and be executed by the runtime.
@@ -43,6 +99,15 @@ function isExecutableBlockType(type) {
43
99
  return executableBlockTypes.has(type);
44
100
  }
45
101
 
102
+ //#endregion
103
+ //#region src/blocks/sql-utils.ts
104
+ function convertToEnvironmentVariableName(str) {
105
+ return (/^\d/.test(str) ? `_${str}` : str).toUpperCase().replace(/[^\w]/g, "_");
106
+ }
107
+ function getSqlEnvVarName(integrationId) {
108
+ return `SQL_${integrationId}`;
109
+ }
110
+
46
111
  //#endregion
47
112
  //#region src/deserialize-file/deepnote-file-schema.ts
48
113
  /** Preprocesses any content value to empty string for blocks that don't use content */
@@ -456,7 +521,7 @@ const deepnoteSnapshotSchema = deepnoteFileSchema.extend({
456
521
  *
457
522
  * @param bytes - Raw file bytes as Uint8Array
458
523
  * @returns Decoded UTF-8 string without BOM
459
- * @throws Error if BOM detected or invalid UTF-8 encoding
524
+ * @throws EncodingError if BOM detected or invalid UTF-8 encoding
460
525
  *
461
526
  * @example
462
527
  * ```typescript
@@ -466,11 +531,11 @@ const deepnoteSnapshotSchema = deepnoteFileSchema.extend({
466
531
  * ```
467
532
  */
468
533
  function decodeUtf8NoBom(bytes) {
469
- if (bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) throw new Error("UTF-8 BOM detected in Deepnote file - files must be UTF-8 without BOM");
534
+ if (bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) throw new EncodingError("UTF-8 BOM detected in Deepnote file - files must be UTF-8 without BOM");
470
535
  try {
471
536
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
472
537
  } catch {
473
- throw new Error("Invalid UTF-8 encoding detected in Deepnote file");
538
+ throw new EncodingError("Invalid UTF-8 encoding detected in Deepnote file");
474
539
  }
475
540
  }
476
541
  /**
@@ -480,10 +545,10 @@ function decodeUtf8NoBom(bytes) {
480
545
  * For proper UTF-8 validation, use decodeUtf8NoBom() on raw bytes before decoding.
481
546
  *
482
547
  * @param yamlContent - Already-decoded YAML string
483
- * @throws Error if BOM prefix detected
548
+ * @throws EncodingError if BOM prefix detected
484
549
  */
485
550
  function validateNoBomPrefix(yamlContent) {
486
- if (yamlContent.charCodeAt(0) === 65279) throw new Error("UTF-8 BOM detected in Deepnote file - files must be UTF-8 without BOM");
551
+ if (yamlContent.charCodeAt(0) === 65279) throw new EncodingError("UTF-8 BOM detected in Deepnote file - files must be UTF-8 without BOM");
487
552
  }
488
553
  /**
489
554
  * Validates that the YAML document doesn't contain prohibited features:
@@ -492,13 +557,13 @@ function validateNoBomPrefix(yamlContent) {
492
557
  * - No custom tags (!tag)
493
558
  */
494
559
  function validateYamlStructure(yamlContent) {
495
- if (/(?:^|\n)\s*(?:-\s+|[\w-]+:\s*)&\w+/.test(yamlContent)) throw new Error("YAML anchors (&) are not allowed in Deepnote files");
496
- if (/(?:^|\n)\s*(?:-\s+|[\w-]+:\s*)\*\w+/.test(yamlContent)) throw new Error("YAML aliases (*) are not allowed in Deepnote files");
497
- if (/<<:/.test(yamlContent)) throw new Error("YAML merge keys (<<) are not allowed in Deepnote files");
560
+ if (/(?:^|\n)\s*(?:-\s+|[\w-]+:\s*)&\w+/.test(yamlContent)) throw new ProhibitedYamlFeatureError("YAML anchors (&) are not allowed in Deepnote files", { feature: "anchor" });
561
+ if (/(?:^|\n)\s*(?:-\s+|[\w-]+:\s*)\*\w+/.test(yamlContent)) throw new ProhibitedYamlFeatureError("YAML aliases (*) are not allowed in Deepnote files", { feature: "alias" });
562
+ if (/<<:/.test(yamlContent)) throw new ProhibitedYamlFeatureError("YAML merge keys (<<) are not allowed in Deepnote files", { feature: "merge-key" });
498
563
  const matches = yamlContent.match(/(?:^|\n)\s*(?:-\s+|[\w-]+:\s*)(![\w/-]+)/gm);
499
564
  if (matches) {
500
565
  const tags = matches.map((m) => m.match(/(![\w/-]+)/)?.[1]).filter(Boolean);
501
- if (tags.length > 0) throw new Error(`YAML tags are not allowed in Deepnote files: ${tags.join(", ")}`);
566
+ if (tags.length > 0) throw new ProhibitedYamlFeatureError(`YAML tags are not allowed in Deepnote files: ${tags.join(", ")}`, { feature: "tag" });
502
567
  }
503
568
  }
504
569
  /**
@@ -513,8 +578,8 @@ function parseAndValidate(yamlContent) {
513
578
  });
514
579
  if (doc.errors.length > 0) {
515
580
  const duplicateKeyError = doc.errors.find((err) => err.message.includes("duplicate") || err.message.includes("key"));
516
- if (duplicateKeyError) throw new Error(`Duplicate keys detected in Deepnote file: ${duplicateKeyError.message}`);
517
- throw new Error(`YAML parsing error: ${doc.errors[0].message}`);
581
+ if (duplicateKeyError) throw new YamlParseError(`Duplicate keys detected in Deepnote file: ${duplicateKeyError.message}`);
582
+ throw new YamlParseError(`YAML parsing error: ${doc.errors[0].message}`);
518
583
  }
519
584
  return doc.toJS();
520
585
  }
@@ -533,8 +598,8 @@ function parseYaml(yamlContent) {
533
598
  validateYamlStructure(yamlContent);
534
599
  return parseAndValidate(yamlContent);
535
600
  } catch (error) {
536
- const message = error instanceof Error ? error.message : String(error);
537
- throw new Error(`Failed to parse Deepnote file: ${message}`);
601
+ if (error instanceof DeepnoteError) throw error;
602
+ throw new ParseError(`Failed to parse Deepnote file: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
538
603
  }
539
604
  }
540
605
 
@@ -548,10 +613,9 @@ function deserializeDeepnoteFile(yamlContent) {
548
613
  const result = deepnoteFileSchema.safeParse(parsed);
549
614
  if (!result.success) {
550
615
  const issue = result.error.issues[0];
551
- if (!issue) throw new Error("Invalid Deepnote file.");
616
+ if (!issue) throw new SchemaValidationError("Invalid Deepnote file.");
552
617
  const path = issue.path.join(".");
553
- const message = path ? `${path}: ${issue.message}` : issue.message;
554
- throw new Error(`Failed to parse the Deepnote file: ${message}.`);
618
+ throw new SchemaValidationError(`Failed to parse the Deepnote file: ${path ? `${path}: ${issue.message}` : issue.message}.`);
555
619
  }
556
620
  return result.data;
557
621
  }
@@ -603,7 +667,7 @@ function createMarkdownForTextBlock(block) {
603
667
  if (block.type === "text-cell-todo") return `- ${block.metadata?.checked ? "[x]" : "[ ]"} ${escapeMarkdown(content)}`;
604
668
  if (block.type === "text-cell-callout") return `> ${escapeMarkdown(content)}`;
605
669
  if (block.type === "text-cell-p") return escapeMarkdown(content);
606
- throw new Error("Unhandled block type.");
670
+ throw new UnsupportedBlockTypeError("Unhandled block type.");
607
671
  }
608
672
  function stripMarkdownFromTextBlock(block) {
609
673
  const content = block.content ?? "";
@@ -614,7 +678,7 @@ function stripMarkdownFromTextBlock(block) {
614
678
  if (block.type === "text-cell-todo") return content.replace(/^-+\s+\[.\]\s+/, "").trim();
615
679
  if (block.type === "text-cell-callout") return content.replace(/^>\s+/, "").trim();
616
680
  if (block.type === "text-cell-p") return content.trim();
617
- throw new Error("Unhandled block type.");
681
+ throw new UnsupportedBlockTypeError("Unhandled block type.");
618
682
  }
619
683
  function createMarkdownForSeparatorBlock(_block) {
620
684
  return "<hr>";
@@ -888,9 +952,9 @@ function createPythonCodeForInputSelectBlock(block) {
888
952
  function createPythonCodeForInputSliderBlock(block) {
889
953
  const sanitizedPythonVariableName = sanitizePythonVariableName(block.metadata.deepnote_variable_name);
890
954
  const value = block.metadata.deepnote_variable_value;
891
- if (!/^-?\d+\.?\d*$|^-?\d*\.\d+$/.test(value)) throw new Error(`Invalid numeric value for slider input: "${value}". Expected a valid number (integer or float).`);
955
+ if (!/^-?\d+\.?\d*$|^-?\d*\.\d+$/.test(value)) throw new InvalidValueError(`Invalid numeric value for slider input: "${value}". Expected a valid number (integer or float).`, { value });
892
956
  const numericValue = Number(value);
893
- if (!Number.isFinite(numericValue)) throw new Error(`Invalid numeric value for slider input: "${value}". Value must be finite.`);
957
+ if (!Number.isFinite(numericValue)) throw new InvalidValueError(`Invalid numeric value for slider input: "${value}". Value must be finite.`, { value });
894
958
  return `${sanitizedPythonVariableName} = ${numericValue}`;
895
959
  }
896
960
  function createPythonCodeForInputFileBlock(block) {
@@ -924,7 +988,7 @@ function createPythonCodeForInputDateRangeBlock(block) {
924
988
  return pythonCode.dateRangeCustomDays(sanitizedPythonVariableName, Number(customDays));
925
989
  } else if (isValidRelativeDateInterval(block.metadata.deepnote_variable_value)) {
926
990
  const range = DATE_RANGE_INPUT_RELATIVE_RANGES.find((range$1) => range$1.value === block.metadata.deepnote_variable_value);
927
- if (!range) throw new Error(`Invalid relative date interval: "${block.metadata.deepnote_variable_value}". Expected one of: ${DATE_RANGE_INPUT_RELATIVE_RANGES.map((r) => r.value).join(", ")}.`);
991
+ if (!range) throw new InvalidValueError(`Invalid relative date interval: "${block.metadata.deepnote_variable_value}". Expected one of: ${DATE_RANGE_INPUT_RELATIVE_RANGES.map((r) => r.value).join(", ")}.`, { value: block.metadata.deepnote_variable_value });
928
992
  return dedent`
929
993
  ${range.pythonCode(sanitizedPythonVariableName)}`;
930
994
  } else return dedent`
@@ -1003,15 +1067,6 @@ function createPythonCodeForNotebookFunctionBlock(block) {
1003
1067
  `;
1004
1068
  }
1005
1069
 
1006
- //#endregion
1007
- //#region src/blocks/sql-utils.ts
1008
- function convertToEnvironmentVariableName(str) {
1009
- return (/^\d/.test(str) ? `_${str}` : str).toUpperCase().replace(/[^\w]/g, "_");
1010
- }
1011
- function getSqlEnvVarName(integrationId) {
1012
- return `SQL_${integrationId}`;
1013
- }
1014
-
1015
1070
  //#endregion
1016
1071
  //#region src/blocks/sql-blocks.ts
1017
1072
  function createPythonCodeForSqlBlock(block) {
@@ -1083,4 +1138,4 @@ function createPythonCode(block, executionContext) {
1083
1138
  }
1084
1139
 
1085
1140
  //#endregion
1086
- export { UnsupportedBlockTypeError, createMarkdown, createPythonCode, decodeUtf8NoBom, deepnoteBlockSchema, deepnoteFileSchema, deepnoteSnapshotSchema, deserializeDeepnoteFile, environmentSchema, executionErrorSchema, executionSchema, executionSummarySchema, isExecutableBlock, isExecutableBlockType, parseYaml, stripMarkdown };
1141
+ export { DeepnoteError, EncodingError, INPUT_BLOCK_TYPES, InvalidValueError, ParseError, ProhibitedYamlFeatureError, SchemaValidationError, UnsupportedBlockTypeError, YamlParseError, convertToEnvironmentVariableName, createMarkdown, createPythonCode, decodeUtf8NoBom, deepnoteBlockSchema, deepnoteFileSchema, deepnoteSnapshotSchema, deserializeDeepnoteFile, environmentSchema, executionErrorSchema, executionSchema, executionSummarySchema, getSqlEnvVarName, isExecutableBlock, isExecutableBlockType, parseYaml, stripMarkdown };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepnote/blocks",
3
- "version": "3.2.1",
3
+ "version": "4.0.0",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "repository": {