@deepnote/blocks 1.4.0 → 3.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.js CHANGED
@@ -3,20 +3,320 @@ import { parseDocument } from "yaml";
3
3
  import { dedent } from "ts-dedent";
4
4
 
5
5
  //#region src/deserialize-file/deepnote-file-schema.ts
6
- const deepnoteBlockSchema = z.object({
7
- blockGroup: z.string().optional(),
8
- content: z.string().optional(),
9
- contentHash: z.string().regex(/^(md5|sha256):[a-f0-9]+$/i).optional(),
10
- executionCount: z.number().optional(),
11
- executionFinishedAt: z.string().datetime().optional(),
12
- executionStartedAt: z.string().datetime().optional(),
6
+ /** Preprocesses any content value to empty string for blocks that don't use content */
7
+ const emptyContent = () => z.preprocess(() => "", z.literal("").optional());
8
+ const baseBlockMetadataSchema = z.object({
9
+ deepnote_app_is_code_hidden: z.boolean().optional(),
10
+ deepnote_app_is_output_hidden: z.boolean().optional(),
11
+ deepnote_app_block_visible: z.boolean().optional(),
12
+ deepnote_app_block_width: z.number().optional(),
13
+ deepnote_app_block_group_id: z.string().nullable().optional(),
14
+ deepnote_app_block_subgroup_id: z.string().optional(),
15
+ deepnote_app_block_order: z.number().optional()
16
+ }).passthrough();
17
+ const executableBlockMetadataSchema = baseBlockMetadataSchema.extend({
18
+ allow_embed: z.union([z.boolean(), z.enum([
19
+ "code_output",
20
+ "code",
21
+ "output"
22
+ ])]).optional(),
23
+ is_code_hidden: z.boolean().optional(),
24
+ is_output_hidden: z.boolean().optional(),
25
+ output_cleared: z.boolean().optional(),
26
+ execution_start: z.number().optional(),
27
+ execution_millis: z.number().optional(),
28
+ source_hash: z.string().optional(),
29
+ execution_context_id: z.string().optional(),
30
+ deepnote_cell_height: z.number().optional(),
31
+ deepnote_output_heights: z.array(z.number().nullable()).optional(),
32
+ deepnote_table_state: z.record(z.any()).optional(),
33
+ last_executed_function_notebook_id: z.string().optional(),
34
+ last_function_run_started_at: z.number().optional(),
35
+ function_notebook_export_states: z.record(z.any()).optional()
36
+ }).passthrough();
37
+ const textCellMetadataSchema = baseBlockMetadataSchema.extend({
38
+ is_collapsed: z.boolean().optional(),
39
+ formattedRanges: z.array(z.any()).optional()
40
+ }).passthrough();
41
+ const baseInputMetadataSchema = executableBlockMetadataSchema.extend({
42
+ deepnote_variable_name: z.string().default("unnamed_variable"),
43
+ deepnote_input_label: z.string().optional()
44
+ });
45
+ const baseBlockFields = {
13
46
  id: z.string(),
14
- metadata: z.record(z.any()).optional(),
15
- outputs: z.array(z.any()).optional(),
47
+ blockGroup: z.string(),
16
48
  sortingKey: z.string(),
17
- type: z.string(),
49
+ contentHash: z.string().regex(/^(md5|sha256):[a-f0-9]+$/i).optional(),
18
50
  version: z.number().optional()
51
+ };
52
+ const executableBlockFields = {
53
+ ...baseBlockFields,
54
+ executionCount: z.number().nullable().optional(),
55
+ executionFinishedAt: z.string().datetime().optional(),
56
+ executionStartedAt: z.string().datetime().optional(),
57
+ outputs: z.array(z.any()).optional()
58
+ };
59
+ const markdownBlockSchema = z.object({
60
+ ...baseBlockFields,
61
+ type: z.literal("markdown"),
62
+ content: z.string().optional(),
63
+ metadata: baseBlockMetadataSchema.extend({ deepnote_cell_height: z.number().optional() }).default({})
64
+ });
65
+ const imageBlockSchema = z.object({
66
+ ...baseBlockFields,
67
+ type: z.literal("image"),
68
+ content: emptyContent(),
69
+ metadata: baseBlockMetadataSchema.extend({
70
+ deepnote_img_src: z.string().optional(),
71
+ deepnote_img_width: z.enum([
72
+ "actual",
73
+ "50%",
74
+ "75%",
75
+ "100%"
76
+ ]).optional(),
77
+ deepnote_img_alignment: z.enum([
78
+ "left",
79
+ "center",
80
+ "right"
81
+ ]).optional()
82
+ }).default({})
83
+ });
84
+ const separatorBlockSchema = z.object({
85
+ ...baseBlockFields,
86
+ type: z.literal("separator"),
87
+ content: emptyContent(),
88
+ metadata: baseBlockMetadataSchema.default({})
89
+ });
90
+ const textCellH1BlockSchema = z.object({
91
+ ...baseBlockFields,
92
+ type: z.literal("text-cell-h1"),
93
+ content: z.string().optional(),
94
+ metadata: textCellMetadataSchema.default({})
95
+ });
96
+ const textCellH2BlockSchema = z.object({
97
+ ...baseBlockFields,
98
+ type: z.literal("text-cell-h2"),
99
+ content: z.string().optional(),
100
+ metadata: textCellMetadataSchema.default({})
101
+ });
102
+ const textCellH3BlockSchema = z.object({
103
+ ...baseBlockFields,
104
+ type: z.literal("text-cell-h3"),
105
+ content: z.string().optional(),
106
+ metadata: textCellMetadataSchema.default({})
107
+ });
108
+ const textCellPBlockSchema = z.object({
109
+ ...baseBlockFields,
110
+ type: z.literal("text-cell-p"),
111
+ content: z.string().optional(),
112
+ metadata: textCellMetadataSchema.default({})
113
+ });
114
+ const textCellBulletBlockSchema = z.object({
115
+ ...baseBlockFields,
116
+ type: z.literal("text-cell-bullet"),
117
+ content: z.string().optional(),
118
+ metadata: textCellMetadataSchema.default({})
119
+ });
120
+ const textCellTodoBlockSchema = z.object({
121
+ ...baseBlockFields,
122
+ type: z.literal("text-cell-todo"),
123
+ content: z.string().optional(),
124
+ metadata: textCellMetadataSchema.extend({ checked: z.boolean().optional() }).default({})
125
+ });
126
+ const textCellCalloutBlockSchema = z.object({
127
+ ...baseBlockFields,
128
+ type: z.literal("text-cell-callout"),
129
+ content: z.string().optional(),
130
+ metadata: textCellMetadataSchema.extend({ color: z.enum([
131
+ "blue",
132
+ "green",
133
+ "yellow",
134
+ "red",
135
+ "purple"
136
+ ]).optional() }).default({})
137
+ });
138
+ const codeBlockSchema = z.object({
139
+ ...executableBlockFields,
140
+ type: z.literal("code"),
141
+ content: z.string().optional(),
142
+ metadata: executableBlockMetadataSchema.extend({ function_export_name: z.string().optional() }).default({})
143
+ });
144
+ const sqlBlockSchema = z.object({
145
+ ...executableBlockFields,
146
+ type: z.literal("sql"),
147
+ content: z.string().optional(),
148
+ metadata: executableBlockMetadataSchema.extend({
149
+ deepnote_variable_name: z.string().optional(),
150
+ deepnote_return_variable_type: z.enum(["dataframe", "query_preview"]).optional(),
151
+ sql_integration_id: z.string().optional(),
152
+ is_compiled_sql_query_visible: z.boolean().optional(),
153
+ function_export_name: z.string().optional()
154
+ }).default({})
155
+ });
156
+ const notebookFunctionBlockSchema = z.object({
157
+ ...executableBlockFields,
158
+ type: z.literal("notebook-function"),
159
+ content: emptyContent(),
160
+ metadata: executableBlockMetadataSchema.extend({
161
+ function_notebook_id: z.string().nullable(),
162
+ function_notebook_inputs: z.record(z.any()).optional(),
163
+ function_notebook_export_mappings: z.record(z.any()).optional()
164
+ }).default({ function_notebook_id: null })
165
+ });
166
+ const visualizationBlockSchema = z.object({
167
+ ...executableBlockFields,
168
+ type: z.literal("visualization"),
169
+ content: emptyContent(),
170
+ metadata: executableBlockMetadataSchema.extend({
171
+ deepnote_variable_name: z.string().optional(),
172
+ deepnote_visualization_spec: z.record(z.any()).optional(),
173
+ deepnote_config_collapsed: z.boolean().optional(),
174
+ deepnote_chart_height: z.number().optional(),
175
+ deepnote_chart_filter: z.record(z.any()).optional()
176
+ }).default({})
177
+ });
178
+ const buttonBlockSchema = z.object({
179
+ ...executableBlockFields,
180
+ type: z.literal("button"),
181
+ content: emptyContent(),
182
+ metadata: executableBlockMetadataSchema.extend({
183
+ deepnote_button_title: z.string().optional(),
184
+ deepnote_button_color_scheme: z.enum([
185
+ "blue",
186
+ "red",
187
+ "neutral",
188
+ "green",
189
+ "yellow"
190
+ ]).optional(),
191
+ deepnote_button_behavior: z.enum(["run", "set_variable"]).optional(),
192
+ deepnote_variable_name: z.string().optional()
193
+ }).default({})
194
+ });
195
+ const bigNumberBlockSchema = z.object({
196
+ ...executableBlockFields,
197
+ type: z.literal("big-number"),
198
+ content: z.string().optional(),
199
+ metadata: executableBlockMetadataSchema.extend({
200
+ deepnote_big_number_title: z.string().default(""),
201
+ deepnote_big_number_value: z.string().default(""),
202
+ deepnote_big_number_format: z.string().default(""),
203
+ deepnote_big_number_comparison_enabled: z.boolean().optional(),
204
+ deepnote_big_number_comparison_title: z.string().optional(),
205
+ deepnote_big_number_comparison_value: z.string().optional(),
206
+ deepnote_big_number_comparison_type: z.string().optional(),
207
+ deepnote_big_number_comparison_format: z.string().optional()
208
+ }).default({})
209
+ });
210
+ const inputTextBlockSchema = z.object({
211
+ ...executableBlockFields,
212
+ type: z.literal("input-text"),
213
+ content: z.string().optional(),
214
+ metadata: baseInputMetadataSchema.extend({
215
+ deepnote_variable_value: z.string().default(""),
216
+ deepnote_variable_default_value: z.preprocess((val) => val === null ? void 0 : val, z.string().optional())
217
+ }).default({})
218
+ });
219
+ const inputTextareaBlockSchema = z.object({
220
+ ...executableBlockFields,
221
+ type: z.literal("input-textarea"),
222
+ content: z.string().optional(),
223
+ metadata: baseInputMetadataSchema.extend({
224
+ deepnote_variable_value: z.string().default(""),
225
+ deepnote_variable_default_value: z.preprocess((val) => val === null ? void 0 : val, z.string().optional())
226
+ }).default({})
227
+ });
228
+ const inputCheckboxBlockSchema = z.object({
229
+ ...executableBlockFields,
230
+ type: z.literal("input-checkbox"),
231
+ content: z.string().optional(),
232
+ metadata: baseInputMetadataSchema.extend({
233
+ deepnote_variable_value: z.boolean().default(false),
234
+ deepnote_variable_default_value: z.preprocess((val) => val === null ? void 0 : val, z.boolean().optional()),
235
+ deepnote_input_checkbox_label: z.string().optional()
236
+ }).default({})
237
+ });
238
+ const inputSelectBlockSchema = z.object({
239
+ ...executableBlockFields,
240
+ type: z.literal("input-select"),
241
+ content: z.string().optional(),
242
+ metadata: baseInputMetadataSchema.extend({
243
+ deepnote_variable_value: z.union([z.string(), z.array(z.string())]).default(""),
244
+ deepnote_variable_default_value: z.preprocess((val) => val === null ? void 0 : val, z.union([z.string(), z.array(z.string())]).optional()),
245
+ deepnote_variable_options: z.array(z.string()).default([]),
246
+ deepnote_variable_custom_options: z.array(z.string()).default([]),
247
+ deepnote_variable_selected_variable: z.string().default(""),
248
+ deepnote_variable_select_type: z.enum(["from-options", "from-variable"]).default("from-options"),
249
+ deepnote_allow_multiple_values: z.boolean().optional(),
250
+ deepnote_allow_empty_values: z.boolean().optional()
251
+ }).default({})
252
+ });
253
+ const inputSliderBlockSchema = z.object({
254
+ ...executableBlockFields,
255
+ type: z.literal("input-slider"),
256
+ content: z.string().optional(),
257
+ metadata: baseInputMetadataSchema.extend({
258
+ deepnote_variable_value: z.string().default("0"),
259
+ deepnote_variable_default_value: z.preprocess((val) => val === null ? void 0 : val, z.string().optional()),
260
+ deepnote_slider_min_value: z.number().default(0),
261
+ deepnote_slider_max_value: z.number().default(100),
262
+ deepnote_slider_step: z.number().default(1)
263
+ }).default({})
264
+ });
265
+ const inputDateBlockSchema = z.object({
266
+ ...executableBlockFields,
267
+ type: z.literal("input-date"),
268
+ content: z.string().optional(),
269
+ metadata: baseInputMetadataSchema.extend({
270
+ deepnote_variable_value: z.string().default(""),
271
+ deepnote_variable_default_value: z.preprocess((val) => val === null ? void 0 : val, z.string().optional()),
272
+ deepnote_allow_empty_values: z.boolean().optional(),
273
+ deepnote_input_date_version: z.number().optional()
274
+ }).default({})
275
+ });
276
+ const inputDateRangeBlockSchema = z.object({
277
+ ...executableBlockFields,
278
+ type: z.literal("input-date-range"),
279
+ content: z.string().optional(),
280
+ metadata: baseInputMetadataSchema.extend({
281
+ deepnote_variable_value: z.union([z.tuple([z.string(), z.string()]), z.string()]).default(""),
282
+ deepnote_variable_default_value: z.preprocess((val) => val === null ? void 0 : val, z.union([z.tuple([z.string(), z.string()]), z.string()]).optional())
283
+ }).default({})
284
+ });
285
+ const inputFileBlockSchema = z.object({
286
+ ...executableBlockFields,
287
+ type: z.literal("input-file"),
288
+ content: z.string().optional(),
289
+ metadata: baseInputMetadataSchema.extend({
290
+ deepnote_variable_value: z.string().default(""),
291
+ deepnote_allowed_file_extensions: z.string().optional()
292
+ }).default({})
19
293
  });
294
+ const deepnoteBlockSchema = z.discriminatedUnion("type", [
295
+ markdownBlockSchema,
296
+ imageBlockSchema,
297
+ separatorBlockSchema,
298
+ textCellH1BlockSchema,
299
+ textCellH2BlockSchema,
300
+ textCellH3BlockSchema,
301
+ textCellPBlockSchema,
302
+ textCellBulletBlockSchema,
303
+ textCellTodoBlockSchema,
304
+ textCellCalloutBlockSchema,
305
+ codeBlockSchema,
306
+ sqlBlockSchema,
307
+ notebookFunctionBlockSchema,
308
+ visualizationBlockSchema,
309
+ buttonBlockSchema,
310
+ bigNumberBlockSchema,
311
+ inputTextBlockSchema,
312
+ inputTextareaBlockSchema,
313
+ inputCheckboxBlockSchema,
314
+ inputSelectBlockSchema,
315
+ inputSliderBlockSchema,
316
+ inputDateBlockSchema,
317
+ inputDateRangeBlockSchema,
318
+ inputFileBlockSchema
319
+ ]);
20
320
  const environmentSchema = z.object({
21
321
  customImage: z.string().optional(),
22
322
  hash: z.string().optional(),
@@ -228,7 +528,7 @@ function sanitizeAlignment(alignment) {
228
528
  ].includes(alignment.toLowerCase()) ? alignment.toLowerCase() : "";
229
529
  }
230
530
  function createMarkdownForImageBlock(block) {
231
- return `<img src="${escapeHtmlAttribute(block.metadata.deepnote_img_src ?? "")}" width="${sanitizeWidth(block.metadata.deepnote_img_width ?? "")}" align="${sanitizeAlignment(block.metadata.deepnote_img_alignment ?? "")}" />`;
531
+ return `<img src="${escapeHtmlAttribute(block.metadata?.deepnote_img_src ?? "")}" width="${sanitizeWidth(block.metadata?.deepnote_img_width ?? "")}" align="${sanitizeAlignment(block.metadata?.deepnote_img_alignment ?? "")}" />`;
232
532
  }
233
533
  function isImageBlock(block) {
234
534
  return block.type === "image";
@@ -251,23 +551,25 @@ function escapeMarkdown(text) {
251
551
  return text.replace(/([\\`*_{}[\]()#+\-.!|>])/g, "\\$1");
252
552
  }
253
553
  function createMarkdownForTextBlock(block) {
254
- if (block.type === "text-cell-h1") return `# ${escapeMarkdown(block.content)}`;
255
- if (block.type === "text-cell-h2") return `## ${escapeMarkdown(block.content)}`;
256
- if (block.type === "text-cell-h3") return `### ${escapeMarkdown(block.content)}`;
257
- if (block.type === "text-cell-bullet") return `- ${escapeMarkdown(block.content)}`;
258
- if (block.type === "text-cell-todo") return `- ${block.metadata.checked ? "[x]" : "[ ]"} ${escapeMarkdown(block.content)}`;
259
- if (block.type === "text-cell-callout") return `> ${escapeMarkdown(block.content)}`;
260
- if (block.type === "text-cell-p") return escapeMarkdown(block.content);
554
+ const content = block.content ?? "";
555
+ if (block.type === "text-cell-h1") return `# ${escapeMarkdown(content)}`;
556
+ if (block.type === "text-cell-h2") return `## ${escapeMarkdown(content)}`;
557
+ if (block.type === "text-cell-h3") return `### ${escapeMarkdown(content)}`;
558
+ if (block.type === "text-cell-bullet") return `- ${escapeMarkdown(content)}`;
559
+ if (block.type === "text-cell-todo") return `- ${block.metadata?.checked ? "[x]" : "[ ]"} ${escapeMarkdown(content)}`;
560
+ if (block.type === "text-cell-callout") return `> ${escapeMarkdown(content)}`;
561
+ if (block.type === "text-cell-p") return escapeMarkdown(content);
261
562
  throw new Error("Unhandled block type.");
262
563
  }
263
564
  function stripMarkdownFromTextBlock(block) {
264
- if (block.type === "text-cell-h1") return block.content.replace(/^#\s+/, "").trim();
265
- if (block.type === "text-cell-h2") return block.content.replace(/^##\s+/, "").trim();
266
- if (block.type === "text-cell-h3") return block.content.replace(/^#{3,6}\s+/, "").trim();
267
- if (block.type === "text-cell-bullet") return block.content.replace(/^-+\s+/, "").trim();
268
- if (block.type === "text-cell-todo") return block.content.replace(/^-+\s+\[.\]\s+/, "").trim();
269
- if (block.type === "text-cell-callout") return block.content.replace(/^>\s+/, "").trim();
270
- if (block.type === "text-cell-p") return block.content.trim();
565
+ const content = block.content ?? "";
566
+ if (block.type === "text-cell-h1") return content.replace(/^#\s+/, "").trim();
567
+ if (block.type === "text-cell-h2") return content.replace(/^##\s+/, "").trim();
568
+ if (block.type === "text-cell-h3") return content.replace(/^#{3,6}\s+/, "").trim();
569
+ if (block.type === "text-cell-bullet") return content.replace(/^-+\s+/, "").trim();
570
+ if (block.type === "text-cell-todo") return content.replace(/^-+\s+\[.\]\s+/, "").trim();
571
+ if (block.type === "text-cell-callout") return content.replace(/^>\s+/, "").trim();
572
+ if (block.type === "text-cell-p") return content.trim();
271
573
  throw new Error("Unhandled block type.");
272
574
  }
273
575
  function createMarkdownForSeparatorBlock(_block) {
@@ -447,7 +749,7 @@ function isBigNumberBlock(block) {
447
749
  //#endregion
448
750
  //#region src/blocks/button-blocks.ts
449
751
  function createPythonCodeForButtonBlock(block, executionContext) {
450
- if (block.metadata.deepnote_button_behavior === "set_variable" && block.metadata.deepnote_variable_name) {
752
+ if (block.metadata?.deepnote_button_behavior === "set_variable" && block.metadata?.deepnote_variable_name) {
451
753
  const sanitizedPythonVariableName = sanitizePythonVariableName(block.metadata.deepnote_variable_name);
452
754
  if (executionContext?.variableContext?.includes(sanitizedPythonVariableName)) return pythonCode.setVariableContextValue(sanitizedPythonVariableName, true);
453
755
  return pythonCode.setVariableContextValue(sanitizedPythonVariableName, false);
@@ -461,7 +763,7 @@ function isButtonBlock(block) {
461
763
  //#endregion
462
764
  //#region src/blocks/data-frame.ts
463
765
  function createDataFrameConfig(block) {
464
- const tableState = block.metadata.deepnote_table_state ?? {};
766
+ const tableState = block.metadata?.deepnote_table_state ?? {};
465
767
  const tableStateAsJson = JSON.stringify(tableState);
466
768
  return dedent`
467
769
  if '_dntk' in globals():
@@ -622,11 +924,11 @@ function getSqlEnvVarName(integrationId) {
622
924
  //#endregion
623
925
  //#region src/blocks/sql-blocks.ts
624
926
  function createPythonCodeForSqlBlock(block) {
625
- const query = block.content;
626
- const pythonVariableName = block.metadata.deepnote_variable_name;
927
+ const query = block.content ?? "";
928
+ const pythonVariableName = block.metadata?.deepnote_variable_name;
627
929
  const sanitizedPythonVariableName = pythonVariableName !== void 0 ? sanitizePythonVariableName(pythonVariableName) || "input_1" : void 0;
628
- const returnVariableType = block.metadata.deepnote_return_variable_type ?? "dataframe";
629
- const integrationId = block.metadata.sql_integration_id;
930
+ const returnVariableType = block.metadata?.deepnote_return_variable_type ?? "dataframe";
931
+ const integrationId = block.metadata?.sql_integration_id;
630
932
  const connectionEnvVarName = integrationId ? convertToEnvironmentVariableName(getSqlEnvVarName(integrationId)) : "SQL_ALCHEMY_JSON_ENV_VAR";
631
933
  const escapedQuery = escapePythonString(query);
632
934
  const dataFrameConfig = createDataFrameConfig(block);
@@ -658,9 +960,9 @@ function isSqlBlock(block) {
658
960
  //#endregion
659
961
  //#region src/blocks/visualization-blocks.ts
660
962
  function createPythonCodeForVisualizationBlock(block) {
661
- const variableName = block.metadata.deepnote_variable_name;
662
- const spec = block.metadata.deepnote_visualization_spec;
663
- const filters = block.metadata.deepnote_chart_filter?.advancedFilters ?? [];
963
+ const variableName = block.metadata?.deepnote_variable_name;
964
+ const spec = block.metadata?.deepnote_visualization_spec;
965
+ const filters = block.metadata?.deepnote_chart_filter?.advancedFilters ?? [];
664
966
  if (!variableName || !spec) return "";
665
967
  const sanitizedVariableName = sanitizePythonVariableName(variableName);
666
968
  return pythonCode.executeVisualization(sanitizedVariableName, JSON.stringify(spec), JSON.stringify(filters));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepnote/blocks",
3
- "version": "1.4.0",
3
+ "version": "3.0.0",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "repository": {