@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.cjs CHANGED
@@ -29,20 +29,320 @@ let ts_dedent = require("ts-dedent");
29
29
  ts_dedent = __toESM(ts_dedent);
30
30
 
31
31
  //#region src/deserialize-file/deepnote-file-schema.ts
32
- const deepnoteBlockSchema = zod.z.object({
33
- blockGroup: zod.z.string().optional(),
34
- content: zod.z.string().optional(),
35
- contentHash: zod.z.string().regex(/^(md5|sha256):[a-f0-9]+$/i).optional(),
36
- executionCount: zod.z.number().optional(),
37
- executionFinishedAt: zod.z.string().datetime().optional(),
38
- executionStartedAt: zod.z.string().datetime().optional(),
32
+ /** Preprocesses any content value to empty string for blocks that don't use content */
33
+ const emptyContent = () => zod.z.preprocess(() => "", zod.z.literal("").optional());
34
+ const baseBlockMetadataSchema = zod.z.object({
35
+ deepnote_app_is_code_hidden: zod.z.boolean().optional(),
36
+ deepnote_app_is_output_hidden: zod.z.boolean().optional(),
37
+ deepnote_app_block_visible: zod.z.boolean().optional(),
38
+ deepnote_app_block_width: zod.z.number().optional(),
39
+ deepnote_app_block_group_id: zod.z.string().nullable().optional(),
40
+ deepnote_app_block_subgroup_id: zod.z.string().optional(),
41
+ deepnote_app_block_order: zod.z.number().optional()
42
+ }).passthrough();
43
+ const executableBlockMetadataSchema = baseBlockMetadataSchema.extend({
44
+ allow_embed: zod.z.union([zod.z.boolean(), zod.z.enum([
45
+ "code_output",
46
+ "code",
47
+ "output"
48
+ ])]).optional(),
49
+ is_code_hidden: zod.z.boolean().optional(),
50
+ is_output_hidden: zod.z.boolean().optional(),
51
+ output_cleared: zod.z.boolean().optional(),
52
+ execution_start: zod.z.number().optional(),
53
+ execution_millis: zod.z.number().optional(),
54
+ source_hash: zod.z.string().optional(),
55
+ execution_context_id: zod.z.string().optional(),
56
+ deepnote_cell_height: zod.z.number().optional(),
57
+ deepnote_output_heights: zod.z.array(zod.z.number().nullable()).optional(),
58
+ deepnote_table_state: zod.z.record(zod.z.any()).optional(),
59
+ last_executed_function_notebook_id: zod.z.string().optional(),
60
+ last_function_run_started_at: zod.z.number().optional(),
61
+ function_notebook_export_states: zod.z.record(zod.z.any()).optional()
62
+ }).passthrough();
63
+ const textCellMetadataSchema = baseBlockMetadataSchema.extend({
64
+ is_collapsed: zod.z.boolean().optional(),
65
+ formattedRanges: zod.z.array(zod.z.any()).optional()
66
+ }).passthrough();
67
+ const baseInputMetadataSchema = executableBlockMetadataSchema.extend({
68
+ deepnote_variable_name: zod.z.string().default("unnamed_variable"),
69
+ deepnote_input_label: zod.z.string().optional()
70
+ });
71
+ const baseBlockFields = {
39
72
  id: zod.z.string(),
40
- metadata: zod.z.record(zod.z.any()).optional(),
41
- outputs: zod.z.array(zod.z.any()).optional(),
73
+ blockGroup: zod.z.string(),
42
74
  sortingKey: zod.z.string(),
43
- type: zod.z.string(),
75
+ contentHash: zod.z.string().regex(/^(md5|sha256):[a-f0-9]+$/i).optional(),
44
76
  version: zod.z.number().optional()
77
+ };
78
+ const executableBlockFields = {
79
+ ...baseBlockFields,
80
+ executionCount: zod.z.number().nullable().optional(),
81
+ executionFinishedAt: zod.z.string().datetime().optional(),
82
+ executionStartedAt: zod.z.string().datetime().optional(),
83
+ outputs: zod.z.array(zod.z.any()).optional()
84
+ };
85
+ const markdownBlockSchema = zod.z.object({
86
+ ...baseBlockFields,
87
+ type: zod.z.literal("markdown"),
88
+ content: zod.z.string().optional(),
89
+ metadata: baseBlockMetadataSchema.extend({ deepnote_cell_height: zod.z.number().optional() }).default({})
90
+ });
91
+ const imageBlockSchema = zod.z.object({
92
+ ...baseBlockFields,
93
+ type: zod.z.literal("image"),
94
+ content: emptyContent(),
95
+ metadata: baseBlockMetadataSchema.extend({
96
+ deepnote_img_src: zod.z.string().optional(),
97
+ deepnote_img_width: zod.z.enum([
98
+ "actual",
99
+ "50%",
100
+ "75%",
101
+ "100%"
102
+ ]).optional(),
103
+ deepnote_img_alignment: zod.z.enum([
104
+ "left",
105
+ "center",
106
+ "right"
107
+ ]).optional()
108
+ }).default({})
109
+ });
110
+ const separatorBlockSchema = zod.z.object({
111
+ ...baseBlockFields,
112
+ type: zod.z.literal("separator"),
113
+ content: emptyContent(),
114
+ metadata: baseBlockMetadataSchema.default({})
115
+ });
116
+ const textCellH1BlockSchema = zod.z.object({
117
+ ...baseBlockFields,
118
+ type: zod.z.literal("text-cell-h1"),
119
+ content: zod.z.string().optional(),
120
+ metadata: textCellMetadataSchema.default({})
121
+ });
122
+ const textCellH2BlockSchema = zod.z.object({
123
+ ...baseBlockFields,
124
+ type: zod.z.literal("text-cell-h2"),
125
+ content: zod.z.string().optional(),
126
+ metadata: textCellMetadataSchema.default({})
127
+ });
128
+ const textCellH3BlockSchema = zod.z.object({
129
+ ...baseBlockFields,
130
+ type: zod.z.literal("text-cell-h3"),
131
+ content: zod.z.string().optional(),
132
+ metadata: textCellMetadataSchema.default({})
133
+ });
134
+ const textCellPBlockSchema = zod.z.object({
135
+ ...baseBlockFields,
136
+ type: zod.z.literal("text-cell-p"),
137
+ content: zod.z.string().optional(),
138
+ metadata: textCellMetadataSchema.default({})
139
+ });
140
+ const textCellBulletBlockSchema = zod.z.object({
141
+ ...baseBlockFields,
142
+ type: zod.z.literal("text-cell-bullet"),
143
+ content: zod.z.string().optional(),
144
+ metadata: textCellMetadataSchema.default({})
145
+ });
146
+ const textCellTodoBlockSchema = zod.z.object({
147
+ ...baseBlockFields,
148
+ type: zod.z.literal("text-cell-todo"),
149
+ content: zod.z.string().optional(),
150
+ metadata: textCellMetadataSchema.extend({ checked: zod.z.boolean().optional() }).default({})
151
+ });
152
+ const textCellCalloutBlockSchema = zod.z.object({
153
+ ...baseBlockFields,
154
+ type: zod.z.literal("text-cell-callout"),
155
+ content: zod.z.string().optional(),
156
+ metadata: textCellMetadataSchema.extend({ color: zod.z.enum([
157
+ "blue",
158
+ "green",
159
+ "yellow",
160
+ "red",
161
+ "purple"
162
+ ]).optional() }).default({})
163
+ });
164
+ const codeBlockSchema = zod.z.object({
165
+ ...executableBlockFields,
166
+ type: zod.z.literal("code"),
167
+ content: zod.z.string().optional(),
168
+ metadata: executableBlockMetadataSchema.extend({ function_export_name: zod.z.string().optional() }).default({})
169
+ });
170
+ const sqlBlockSchema = zod.z.object({
171
+ ...executableBlockFields,
172
+ type: zod.z.literal("sql"),
173
+ content: zod.z.string().optional(),
174
+ metadata: executableBlockMetadataSchema.extend({
175
+ deepnote_variable_name: zod.z.string().optional(),
176
+ deepnote_return_variable_type: zod.z.enum(["dataframe", "query_preview"]).optional(),
177
+ sql_integration_id: zod.z.string().optional(),
178
+ is_compiled_sql_query_visible: zod.z.boolean().optional(),
179
+ function_export_name: zod.z.string().optional()
180
+ }).default({})
181
+ });
182
+ const notebookFunctionBlockSchema = zod.z.object({
183
+ ...executableBlockFields,
184
+ type: zod.z.literal("notebook-function"),
185
+ content: emptyContent(),
186
+ metadata: executableBlockMetadataSchema.extend({
187
+ function_notebook_id: zod.z.string().nullable(),
188
+ function_notebook_inputs: zod.z.record(zod.z.any()).optional(),
189
+ function_notebook_export_mappings: zod.z.record(zod.z.any()).optional()
190
+ }).default({ function_notebook_id: null })
191
+ });
192
+ const visualizationBlockSchema = zod.z.object({
193
+ ...executableBlockFields,
194
+ type: zod.z.literal("visualization"),
195
+ content: emptyContent(),
196
+ metadata: executableBlockMetadataSchema.extend({
197
+ deepnote_variable_name: zod.z.string().optional(),
198
+ deepnote_visualization_spec: zod.z.record(zod.z.any()).optional(),
199
+ deepnote_config_collapsed: zod.z.boolean().optional(),
200
+ deepnote_chart_height: zod.z.number().optional(),
201
+ deepnote_chart_filter: zod.z.record(zod.z.any()).optional()
202
+ }).default({})
203
+ });
204
+ const buttonBlockSchema = zod.z.object({
205
+ ...executableBlockFields,
206
+ type: zod.z.literal("button"),
207
+ content: emptyContent(),
208
+ metadata: executableBlockMetadataSchema.extend({
209
+ deepnote_button_title: zod.z.string().optional(),
210
+ deepnote_button_color_scheme: zod.z.enum([
211
+ "blue",
212
+ "red",
213
+ "neutral",
214
+ "green",
215
+ "yellow"
216
+ ]).optional(),
217
+ deepnote_button_behavior: zod.z.enum(["run", "set_variable"]).optional(),
218
+ deepnote_variable_name: zod.z.string().optional()
219
+ }).default({})
220
+ });
221
+ const bigNumberBlockSchema = zod.z.object({
222
+ ...executableBlockFields,
223
+ type: zod.z.literal("big-number"),
224
+ content: zod.z.string().optional(),
225
+ metadata: executableBlockMetadataSchema.extend({
226
+ deepnote_big_number_title: zod.z.string().default(""),
227
+ deepnote_big_number_value: zod.z.string().default(""),
228
+ deepnote_big_number_format: zod.z.string().default(""),
229
+ deepnote_big_number_comparison_enabled: zod.z.boolean().optional(),
230
+ deepnote_big_number_comparison_title: zod.z.string().optional(),
231
+ deepnote_big_number_comparison_value: zod.z.string().optional(),
232
+ deepnote_big_number_comparison_type: zod.z.string().optional(),
233
+ deepnote_big_number_comparison_format: zod.z.string().optional()
234
+ }).default({})
235
+ });
236
+ const inputTextBlockSchema = zod.z.object({
237
+ ...executableBlockFields,
238
+ type: zod.z.literal("input-text"),
239
+ content: zod.z.string().optional(),
240
+ metadata: baseInputMetadataSchema.extend({
241
+ deepnote_variable_value: zod.z.string().default(""),
242
+ deepnote_variable_default_value: zod.z.preprocess((val) => val === null ? void 0 : val, zod.z.string().optional())
243
+ }).default({})
244
+ });
245
+ const inputTextareaBlockSchema = zod.z.object({
246
+ ...executableBlockFields,
247
+ type: zod.z.literal("input-textarea"),
248
+ content: zod.z.string().optional(),
249
+ metadata: baseInputMetadataSchema.extend({
250
+ deepnote_variable_value: zod.z.string().default(""),
251
+ deepnote_variable_default_value: zod.z.preprocess((val) => val === null ? void 0 : val, zod.z.string().optional())
252
+ }).default({})
253
+ });
254
+ const inputCheckboxBlockSchema = zod.z.object({
255
+ ...executableBlockFields,
256
+ type: zod.z.literal("input-checkbox"),
257
+ content: zod.z.string().optional(),
258
+ metadata: baseInputMetadataSchema.extend({
259
+ deepnote_variable_value: zod.z.boolean().default(false),
260
+ deepnote_variable_default_value: zod.z.preprocess((val) => val === null ? void 0 : val, zod.z.boolean().optional()),
261
+ deepnote_input_checkbox_label: zod.z.string().optional()
262
+ }).default({})
263
+ });
264
+ const inputSelectBlockSchema = zod.z.object({
265
+ ...executableBlockFields,
266
+ type: zod.z.literal("input-select"),
267
+ content: zod.z.string().optional(),
268
+ metadata: baseInputMetadataSchema.extend({
269
+ deepnote_variable_value: zod.z.union([zod.z.string(), zod.z.array(zod.z.string())]).default(""),
270
+ deepnote_variable_default_value: zod.z.preprocess((val) => val === null ? void 0 : val, zod.z.union([zod.z.string(), zod.z.array(zod.z.string())]).optional()),
271
+ deepnote_variable_options: zod.z.array(zod.z.string()).default([]),
272
+ deepnote_variable_custom_options: zod.z.array(zod.z.string()).default([]),
273
+ deepnote_variable_selected_variable: zod.z.string().default(""),
274
+ deepnote_variable_select_type: zod.z.enum(["from-options", "from-variable"]).default("from-options"),
275
+ deepnote_allow_multiple_values: zod.z.boolean().optional(),
276
+ deepnote_allow_empty_values: zod.z.boolean().optional()
277
+ }).default({})
278
+ });
279
+ const inputSliderBlockSchema = zod.z.object({
280
+ ...executableBlockFields,
281
+ type: zod.z.literal("input-slider"),
282
+ content: zod.z.string().optional(),
283
+ metadata: baseInputMetadataSchema.extend({
284
+ deepnote_variable_value: zod.z.string().default("0"),
285
+ deepnote_variable_default_value: zod.z.preprocess((val) => val === null ? void 0 : val, zod.z.string().optional()),
286
+ deepnote_slider_min_value: zod.z.number().default(0),
287
+ deepnote_slider_max_value: zod.z.number().default(100),
288
+ deepnote_slider_step: zod.z.number().default(1)
289
+ }).default({})
290
+ });
291
+ const inputDateBlockSchema = zod.z.object({
292
+ ...executableBlockFields,
293
+ type: zod.z.literal("input-date"),
294
+ content: zod.z.string().optional(),
295
+ metadata: baseInputMetadataSchema.extend({
296
+ deepnote_variable_value: zod.z.string().default(""),
297
+ deepnote_variable_default_value: zod.z.preprocess((val) => val === null ? void 0 : val, zod.z.string().optional()),
298
+ deepnote_allow_empty_values: zod.z.boolean().optional(),
299
+ deepnote_input_date_version: zod.z.number().optional()
300
+ }).default({})
301
+ });
302
+ const inputDateRangeBlockSchema = zod.z.object({
303
+ ...executableBlockFields,
304
+ type: zod.z.literal("input-date-range"),
305
+ content: zod.z.string().optional(),
306
+ metadata: baseInputMetadataSchema.extend({
307
+ deepnote_variable_value: zod.z.union([zod.z.tuple([zod.z.string(), zod.z.string()]), zod.z.string()]).default(""),
308
+ deepnote_variable_default_value: zod.z.preprocess((val) => val === null ? void 0 : val, zod.z.union([zod.z.tuple([zod.z.string(), zod.z.string()]), zod.z.string()]).optional())
309
+ }).default({})
310
+ });
311
+ const inputFileBlockSchema = zod.z.object({
312
+ ...executableBlockFields,
313
+ type: zod.z.literal("input-file"),
314
+ content: zod.z.string().optional(),
315
+ metadata: baseInputMetadataSchema.extend({
316
+ deepnote_variable_value: zod.z.string().default(""),
317
+ deepnote_allowed_file_extensions: zod.z.string().optional()
318
+ }).default({})
45
319
  });
320
+ const deepnoteBlockSchema = zod.z.discriminatedUnion("type", [
321
+ markdownBlockSchema,
322
+ imageBlockSchema,
323
+ separatorBlockSchema,
324
+ textCellH1BlockSchema,
325
+ textCellH2BlockSchema,
326
+ textCellH3BlockSchema,
327
+ textCellPBlockSchema,
328
+ textCellBulletBlockSchema,
329
+ textCellTodoBlockSchema,
330
+ textCellCalloutBlockSchema,
331
+ codeBlockSchema,
332
+ sqlBlockSchema,
333
+ notebookFunctionBlockSchema,
334
+ visualizationBlockSchema,
335
+ buttonBlockSchema,
336
+ bigNumberBlockSchema,
337
+ inputTextBlockSchema,
338
+ inputTextareaBlockSchema,
339
+ inputCheckboxBlockSchema,
340
+ inputSelectBlockSchema,
341
+ inputSliderBlockSchema,
342
+ inputDateBlockSchema,
343
+ inputDateRangeBlockSchema,
344
+ inputFileBlockSchema
345
+ ]);
46
346
  const environmentSchema = zod.z.object({
47
347
  customImage: zod.z.string().optional(),
48
348
  hash: zod.z.string().optional(),
@@ -254,7 +554,7 @@ function sanitizeAlignment(alignment) {
254
554
  ].includes(alignment.toLowerCase()) ? alignment.toLowerCase() : "";
255
555
  }
256
556
  function createMarkdownForImageBlock(block) {
257
- return `<img src="${escapeHtmlAttribute(block.metadata.deepnote_img_src ?? "")}" width="${sanitizeWidth(block.metadata.deepnote_img_width ?? "")}" align="${sanitizeAlignment(block.metadata.deepnote_img_alignment ?? "")}" />`;
557
+ return `<img src="${escapeHtmlAttribute(block.metadata?.deepnote_img_src ?? "")}" width="${sanitizeWidth(block.metadata?.deepnote_img_width ?? "")}" align="${sanitizeAlignment(block.metadata?.deepnote_img_alignment ?? "")}" />`;
258
558
  }
259
559
  function isImageBlock(block) {
260
560
  return block.type === "image";
@@ -277,23 +577,25 @@ function escapeMarkdown(text) {
277
577
  return text.replace(/([\\`*_{}[\]()#+\-.!|>])/g, "\\$1");
278
578
  }
279
579
  function createMarkdownForTextBlock(block) {
280
- if (block.type === "text-cell-h1") return `# ${escapeMarkdown(block.content)}`;
281
- if (block.type === "text-cell-h2") return `## ${escapeMarkdown(block.content)}`;
282
- if (block.type === "text-cell-h3") return `### ${escapeMarkdown(block.content)}`;
283
- if (block.type === "text-cell-bullet") return `- ${escapeMarkdown(block.content)}`;
284
- if (block.type === "text-cell-todo") return `- ${block.metadata.checked ? "[x]" : "[ ]"} ${escapeMarkdown(block.content)}`;
285
- if (block.type === "text-cell-callout") return `> ${escapeMarkdown(block.content)}`;
286
- if (block.type === "text-cell-p") return escapeMarkdown(block.content);
580
+ const content = block.content ?? "";
581
+ if (block.type === "text-cell-h1") return `# ${escapeMarkdown(content)}`;
582
+ if (block.type === "text-cell-h2") return `## ${escapeMarkdown(content)}`;
583
+ if (block.type === "text-cell-h3") return `### ${escapeMarkdown(content)}`;
584
+ if (block.type === "text-cell-bullet") return `- ${escapeMarkdown(content)}`;
585
+ if (block.type === "text-cell-todo") return `- ${block.metadata?.checked ? "[x]" : "[ ]"} ${escapeMarkdown(content)}`;
586
+ if (block.type === "text-cell-callout") return `> ${escapeMarkdown(content)}`;
587
+ if (block.type === "text-cell-p") return escapeMarkdown(content);
287
588
  throw new Error("Unhandled block type.");
288
589
  }
289
590
  function stripMarkdownFromTextBlock(block) {
290
- if (block.type === "text-cell-h1") return block.content.replace(/^#\s+/, "").trim();
291
- if (block.type === "text-cell-h2") return block.content.replace(/^##\s+/, "").trim();
292
- if (block.type === "text-cell-h3") return block.content.replace(/^#{3,6}\s+/, "").trim();
293
- if (block.type === "text-cell-bullet") return block.content.replace(/^-+\s+/, "").trim();
294
- if (block.type === "text-cell-todo") return block.content.replace(/^-+\s+\[.\]\s+/, "").trim();
295
- if (block.type === "text-cell-callout") return block.content.replace(/^>\s+/, "").trim();
296
- if (block.type === "text-cell-p") return block.content.trim();
591
+ const content = block.content ?? "";
592
+ if (block.type === "text-cell-h1") return content.replace(/^#\s+/, "").trim();
593
+ if (block.type === "text-cell-h2") return content.replace(/^##\s+/, "").trim();
594
+ if (block.type === "text-cell-h3") return content.replace(/^#{3,6}\s+/, "").trim();
595
+ if (block.type === "text-cell-bullet") return content.replace(/^-+\s+/, "").trim();
596
+ if (block.type === "text-cell-todo") return content.replace(/^-+\s+\[.\]\s+/, "").trim();
597
+ if (block.type === "text-cell-callout") return content.replace(/^>\s+/, "").trim();
598
+ if (block.type === "text-cell-p") return content.trim();
297
599
  throw new Error("Unhandled block type.");
298
600
  }
299
601
  function createMarkdownForSeparatorBlock(_block) {
@@ -473,7 +775,7 @@ function isBigNumberBlock(block) {
473
775
  //#endregion
474
776
  //#region src/blocks/button-blocks.ts
475
777
  function createPythonCodeForButtonBlock(block, executionContext) {
476
- if (block.metadata.deepnote_button_behavior === "set_variable" && block.metadata.deepnote_variable_name) {
778
+ if (block.metadata?.deepnote_button_behavior === "set_variable" && block.metadata?.deepnote_variable_name) {
477
779
  const sanitizedPythonVariableName = sanitizePythonVariableName(block.metadata.deepnote_variable_name);
478
780
  if (executionContext?.variableContext?.includes(sanitizedPythonVariableName)) return pythonCode.setVariableContextValue(sanitizedPythonVariableName, true);
479
781
  return pythonCode.setVariableContextValue(sanitizedPythonVariableName, false);
@@ -487,7 +789,7 @@ function isButtonBlock(block) {
487
789
  //#endregion
488
790
  //#region src/blocks/data-frame.ts
489
791
  function createDataFrameConfig(block) {
490
- const tableState = block.metadata.deepnote_table_state ?? {};
792
+ const tableState = block.metadata?.deepnote_table_state ?? {};
491
793
  const tableStateAsJson = JSON.stringify(tableState);
492
794
  return ts_dedent.dedent`
493
795
  if '_dntk' in globals():
@@ -648,11 +950,11 @@ function getSqlEnvVarName(integrationId) {
648
950
  //#endregion
649
951
  //#region src/blocks/sql-blocks.ts
650
952
  function createPythonCodeForSqlBlock(block) {
651
- const query = block.content;
652
- const pythonVariableName = block.metadata.deepnote_variable_name;
953
+ const query = block.content ?? "";
954
+ const pythonVariableName = block.metadata?.deepnote_variable_name;
653
955
  const sanitizedPythonVariableName = pythonVariableName !== void 0 ? sanitizePythonVariableName(pythonVariableName) || "input_1" : void 0;
654
- const returnVariableType = block.metadata.deepnote_return_variable_type ?? "dataframe";
655
- const integrationId = block.metadata.sql_integration_id;
956
+ const returnVariableType = block.metadata?.deepnote_return_variable_type ?? "dataframe";
957
+ const integrationId = block.metadata?.sql_integration_id;
656
958
  const connectionEnvVarName = integrationId ? convertToEnvironmentVariableName(getSqlEnvVarName(integrationId)) : "SQL_ALCHEMY_JSON_ENV_VAR";
657
959
  const escapedQuery = escapePythonString(query);
658
960
  const dataFrameConfig = createDataFrameConfig(block);
@@ -684,9 +986,9 @@ function isSqlBlock(block) {
684
986
  //#endregion
685
987
  //#region src/blocks/visualization-blocks.ts
686
988
  function createPythonCodeForVisualizationBlock(block) {
687
- const variableName = block.metadata.deepnote_variable_name;
688
- const spec = block.metadata.deepnote_visualization_spec;
689
- const filters = block.metadata.deepnote_chart_filter?.advancedFilters ?? [];
989
+ const variableName = block.metadata?.deepnote_variable_name;
990
+ const spec = block.metadata?.deepnote_visualization_spec;
991
+ const filters = block.metadata?.deepnote_chart_filter?.advancedFilters ?? [];
690
992
  if (!variableName || !spec) return "";
691
993
  const sanitizedVariableName = sanitizePythonVariableName(variableName);
692
994
  return pythonCode.executeVisualization(sanitizedVariableName, JSON.stringify(spec), JSON.stringify(filters));