or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

communication.mderror-handling.mdindex.mdlayout-style.mdnativeview.mdregistry.mdutilities.mdwidget-classes.mdwidget-manager.md
tile.json

utilities.mddocs/

0

# Utilities & Helpers

1

2

A comprehensive set of utility functions for serialization, buffer handling, view management, promise resolution, and common operations used throughout the Jupyter widgets ecosystem.

3

4

## Capabilities

5

6

### Model Serialization

7

8

Utilities for handling widget model references in complex nested data structures.

9

10

```typescript { .api }

11

/**

12

* Recursively replace model ID strings with actual model instances

13

* @param value - Data structure containing model references

14

* @param manager - Widget manager for model resolution

15

* @returns Promise resolving to data with unpacked model instances

16

*/

17

function unpack_models(

18

value: any | Dict<unknown> | string | (Dict<unknown> | string)[],

19

manager?: IWidgetManager

20

): Promise<WidgetModel | Dict<WidgetModel> | WidgetModel[] | any>;

21

22

/**

23

* Recursively replace model instances with their ID strings

24

* @param value - Data structure containing model instances

25

* @param widget - Widget context for serialization

26

* @returns Data with model instances replaced by ID strings

27

*/

28

function pack_models(

29

value: WidgetModel | Dict<WidgetModel> | WidgetModel[] | any,

30

widget?: WidgetModel

31

): any | Dict<unknown> | string | (Dict<unknown> | string)[];

32

```

33

34

**Usage Examples:**

35

36

```typescript

37

// Unpack model references received from kernel

38

const rawData = {

39

title: "My Dashboard",

40

widgets: ["IPY_MODEL_abc123", "IPY_MODEL_def456"],

41

config: {

42

layout: "IPY_MODEL_layout1",

43

theme: "IPY_MODEL_theme1"

44

}

45

};

46

47

const processedData = await unpack_models(rawData, widgetManager);

48

// Now processedData.widgets contains actual WidgetModel instances

49

// processedData.config.layout is a LayoutModel instance

50

51

// Pack models for transmission to kernel

52

const dataToSend = {

53

selectedWidgets: [widget1, widget2],

54

mainLayout: layoutModel

55

};

56

57

const serializedData = pack_models(dataToSend);

58

// Becomes: { selectedWidgets: ["IPY_MODEL_abc123", "IPY_MODEL_def456"], mainLayout: "IPY_MODEL_layout1" }

59

```

60

61

### Binary Buffer Handling

62

63

Functions for managing binary data within JSON-serializable state objects.

64

65

```typescript { .api }

66

/**

67

* Insert binary buffers into a state object at specified paths

68

* @param state - State object to modify

69

* @param buffer_paths - Array of paths where buffers should be placed

70

* @param buffers - Array of binary buffers to insert

71

*/

72

function put_buffers(

73

state: Dict<BufferJSON>,

74

buffer_paths: (string | number)[][],

75

buffers: (DataView | ArrayBuffer | ArrayBufferView | { buffer: ArrayBuffer })[]

76

): void;

77

78

/**

79

* Extract binary buffers from a state object, replacing them with null/removed keys

80

* @param state - State object containing binary data

81

* @returns Object with separated state, buffer paths, and buffers

82

*/

83

function remove_buffers(

84

state: BufferJSON | ISerializeable

85

): ISerializedState;

86

87

/**

88

* Type representing JSON-serializable data that may contain binary buffers

89

*/

90

type BufferJSON =

91

| { [property: string]: BufferJSON }

92

| BufferJSON[]

93

| string

94

| number

95

| boolean

96

| null

97

| ArrayBuffer

98

| DataView;

99

100

/**

101

* Result of buffer extraction

102

*/

103

interface ISerializedState {

104

state: JSONObject;

105

buffers: ArrayBuffer[];

106

buffer_paths: (string | number)[][];

107

}

108

```

109

110

**Usage Examples:**

111

112

```typescript

113

// Prepare data with binary content for transmission

114

const stateWithBuffers = {

115

metadata: { name: "image_data", type: "png" },

116

imageData: new Uint8Array([137, 80, 78, 71, /* ... */]),

117

thumbnails: [

118

new Uint8Array([/* thumb1 */]),

119

new Uint8Array([/* thumb2 */])

120

]

121

};

122

123

// Extract buffers for separate transmission

124

const { state, buffer_paths, buffers } = remove_buffers(stateWithBuffers);

125

// state = { metadata: {...}, thumbnails: [null, null] }

126

// buffer_paths = [["imageData"], ["thumbnails", 0], ["thumbnails", 1]]

127

// buffers = [ArrayBuffer, ArrayBuffer, ArrayBuffer]

128

129

// Reconstruct on receiving end

130

const receivedState = { metadata: {...}, thumbnails: [null, null] };

131

put_buffers(receivedState, buffer_paths, buffers);

132

// receivedState now has binary data restored

133

```

134

135

### View Management

136

137

Utility class for managing ordered collections of views with automatic synchronization.

138

139

```typescript { .api }

140

/**

141

* Utility for managing ordered collections of views

142

*/

143

class ViewList<T> {

144

/**

145

* Create a view list with handlers for view creation and removal

146

* @param create_view - Function to create views from models

147

* @param remove_view - Function to clean up views (null for default removal)

148

* @param context - Context for handler function calls

149

*/

150

constructor(

151

create_view: (model: any, index: any) => T | Promise<T>,

152

remove_view: ((view: T) => void) | null,

153

context: any

154

);

155

156

/**

157

* Initialize the view list with handlers

158

* @param create_view - View creation function

159

* @param remove_view - View removal function

160

* @param context - Execution context

161

*/

162

initialize(

163

create_view: (model: any, index: any) => T | Promise<T>,

164

remove_view: ((view: T) => void) | null,

165

context: any

166

): void;

167

168

/**

169

* Update the view collection to match a new model list

170

* @param new_models - Array of models for the views

171

* @param create_view - Optional override for view creation

172

* @param remove_view - Optional override for view removal

173

* @param context - Optional override for execution context

174

* @returns Promise resolving to array of all views

175

*/

176

update(

177

new_models: any[],

178

create_view?: (model: any, index: any) => T | Promise<T>,

179

remove_view?: (view: T) => void,

180

context?: any

181

): Promise<T[]>;

182

183

/**

184

* Remove all views from the list

185

* @returns Promise that resolves when all views are removed

186

*/

187

remove(): Promise<void>;

188

189

/**

190

* Dispose the view list without removing views (synchronous cleanup)

191

*/

192

dispose(): void;

193

194

// Properties

195

views: Promise<T>[];

196

}

197

```

198

199

**Usage Examples:**

200

201

```typescript

202

// Create view list for managing child widgets

203

const createChildView = async (model: WidgetModel, index: number) => {

204

const view = await this.create_child_view(model);

205

this.childContainer.appendChild(view.el);

206

return view;

207

};

208

209

const removeChildView = (view: WidgetView) => {

210

if (view.el.parentNode) {

211

view.el.parentNode.removeChild(view.el);

212

}

213

view.remove();

214

};

215

216

const childViews = new ViewList(createChildView, removeChildView, this);

217

218

// Update views when model list changes

219

this.listenTo(this.model, 'change:children', () => {

220

childViews.update(this.model.get('children'));

221

});

222

223

// Get all current views

224

const allViews = await Promise.all(childViews.views);

225

226

// Clean up when done

227

await childViews.remove();

228

```

229

230

### Promise Utilities

231

232

Helper functions for working with promises in complex data structures.

233

234

```typescript { .api }

235

/**

236

* Resolve all promises in a dictionary object

237

* @param d - Dictionary containing promises or values

238

* @returns Promise resolving to dictionary with resolved values

239

*/

240

function resolvePromisesDict<V>(

241

d: Dict<PromiseLike<V> | V>

242

): Promise<Dict<V>>;

243

244

/**

245

* Create a promise rejection handler with logging

246

* @param message - Error message to log

247

* @param log - Whether to log the error

248

* @returns Function that logs and re-throws errors

249

*/

250

function reject(message: string, log: boolean): (error: Error) => never;

251

252

/**

253

* Simple dictionary type

254

*/

255

type Dict<T> = { [keys: string]: T };

256

```

257

258

**Usage Examples:**

259

260

```typescript

261

// Resolve multiple async operations

262

const operations = {

263

loadData: fetchUserData(),

264

loadConfig: fetchConfiguration(),

265

loadTheme: fetchThemeSettings()

266

};

267

268

const results = await resolvePromisesDict(operations);

269

// results.loadData, results.loadConfig, results.loadTheme are all resolved

270

271

// Create error handler with context

272

const handleModelError = reject('Failed to create model', true);

273

274

try {

275

const model = await createComplexModel();

276

} catch (error) {

277

handleModelError(error); // Logs "Failed to create model" then re-throws

278

}

279

```

280

281

### Data Manipulation

282

283

Utility functions for common data operations.

284

285

```typescript { .api }

286

/**

287

* Find elements in first array that are not in second array

288

* @param a - First array

289

* @param b - Second array

290

* @returns Elements in a but not in b

291

*/

292

function difference(a: string[], b: string[]): string[];

293

294

/**

295

* Deep equality comparison using lodash

296

* @param a - First value to compare

297

* @param b - Second value to compare

298

* @returns True if values are deeply equal

299

*/

300

function isEqual(a: unknown, b: unknown): boolean;

301

302

/**

303

* Object.assign polyfill for older environments

304

* @param target - Target object

305

* @param sources - Source objects to merge

306

* @returns Merged target object

307

*/

308

const assign: (target: any, ...sources: any[]) => any;

309

310

/**

311

* Generate a UUID using Lumino's UUID implementation

312

* @returns UUID string

313

*/

314

function uuid(): string;

315

```

316

317

**Usage Examples:**

318

319

```typescript

320

// Find differences in arrays

321

const oldClasses = ['widget', 'active', 'highlighted'];

322

const newClasses = ['widget', 'inactive'];

323

const toRemove = difference(oldClasses, newClasses); // ['active', 'highlighted']

324

const toAdd = difference(newClasses, oldClasses); // ['inactive']

325

326

// Deep equality checking

327

const state1 = { user: { name: 'Alice', preferences: { theme: 'dark' } } };

328

const state2 = { user: { name: 'Alice', preferences: { theme: 'dark' } } };

329

console.log(isEqual(state1, state2)); // true

330

331

// Safe object merging

332

const defaults = { timeout: 5000, retries: 3 };

333

const userOptions = { timeout: 10000 };

334

const config = assign({}, defaults, userOptions); // { timeout: 10000, retries: 3 }

335

336

// Generate unique identifiers

337

const widgetId = uuid(); // e.g., "f47ac10b-58cc-4372-a567-0e02b2c3d479"

338

```

339

340

### Type Checking Utilities

341

342

Functions for runtime type checking and validation.

343

344

```typescript { .api }

345

/**

346

* Check if an object has a toJSON method

347

* @param object - Object to check

348

* @returns True if object is serializable

349

*/

350

function isSerializable(object: unknown): object is ISerializeable;

351

352

/**

353

* Check if data is a plain object (not array, null, etc.)

354

* @param data - Data to check

355

* @returns True if data is a plain object

356

*/

357

function isObject(data: BufferJSON): data is Dict<BufferJSON>;

358

359

/**

360

* Interface for objects that can be serialized to JSON

361

*/

362

interface ISerializeable {

363

toJSON(options?: {}): JSONObject;

364

}

365

```

366

367

**Usage Examples:**

368

369

```typescript

370

// Check serializability before processing

371

const processData = (data: unknown) => {

372

if (isSerializable(data)) {

373

const jsonData = data.toJSON();

374

// Process as JSON

375

} else if (isObject(data)) {

376

// Process as plain object

377

Object.keys(data).forEach(key => {

378

processData(data[key]);

379

});

380

}

381

};

382

383

// Type-safe object iteration

384

const handleComplexState = (state: BufferJSON) => {

385

if (isObject(state)) {

386

// TypeScript knows state is Dict<BufferJSON>

387

for (const [key, value] of Object.entries(state)) {

388

console.log(`Processing ${key}:`, value);

389

}

390

}

391

};

392

```

393

394

## Advanced Utility Patterns

395

396

### Batch Operations

397

398

```typescript

399

// Batch model operations with error handling

400

const batchUpdateModels = async (updates: Array<{model: WidgetModel, changes: any}>) => {

401

const operations = updates.map(({model, changes}) =>

402

model.set(changes) && model.save_changes()

403

);

404

405

try {

406

await Promise.all(operations);

407

console.log('All models updated successfully');

408

} catch (error) {

409

reject('Batch update failed', true)(error);

410

}

411

};

412

413

// Batch view creation with ViewList

414

const createViewBatch = async (models: WidgetModel[]) => {

415

const viewList = new ViewList(

416

async (model: WidgetModel) => await createWidgetView(model),

417

(view: WidgetView) => view.remove(),

418

this

419

);

420

421

return await viewList.update(models);

422

};

423

```

424

425

### State Synchronization

426

427

```typescript

428

// Synchronize complex nested state with binary data

429

const syncComplexState = async (localState: any, manager: IWidgetManager) => {

430

// Unpack any model references

431

const withModels = await unpack_models(localState, manager);

432

433

// Handle binary data if present

434

if (withModels._buffer_paths && withModels._buffers) {

435

put_buffers(withModels, withModels._buffer_paths, withModels._buffers);

436

delete withModels._buffer_paths;

437

delete withModels._buffers;

438

}

439

440

return withModels;

441

};

442

443

// Prepare state for transmission

444

const prepareStateForSync = (state: any) => {

445

// Pack model instances to references

446

const packedState = pack_models(state);

447

448

// Extract binary buffers

449

const { state: cleanState, buffer_paths, buffers } = remove_buffers(packedState);

450

451

return {

452

state: cleanState,

453

buffer_paths: buffer_paths,

454

buffers: buffers

455

};

456

};

457

```

458

459

### Error Recovery

460

461

```typescript

462

// Robust operation with retries

463

const robustOperation = async <T>(

464

operation: () => Promise<T>,

465

retries = 3,

466

delay = 1000

467

): Promise<T> => {

468

let lastError: Error;

469

470

for (let attempt = 0; attempt <= retries; attempt++) {

471

try {

472

return await operation();

473

} catch (error) {

474

lastError = error as Error;

475

if (attempt < retries) {

476

await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, attempt)));

477

}

478

}

479

}

480

481

throw reject(`Operation failed after ${retries} attempts`, true)(lastError!);

482

};

483

484

// Safe view cleanup

485

const safeCleanup = async (views: Promise<WidgetView>[]) => {

486

const settledResults = await Promise.allSettled(views);

487

488

settledResults.forEach((result, index) => {

489

if (result.status === 'fulfilled') {

490

try {

491

result.value.remove();

492

} catch (error) {

493

console.warn(`Failed to remove view ${index}:`, error);

494

}

495

} else {

496

console.warn(`View ${index} was rejected:`, result.reason);

497

}

498

});

499

};

500

```

501

502

## Constants and Assets

503

504

### Built-in Assets

505

506

```typescript { .api }

507

/**

508

* SVG icon displayed in error widgets

509

*/

510

const BROKEN_FILE_SVG_ICON: string;

511

```

512

513

**Usage Example:**

514

515

```typescript

516

// Use in custom error display

517

const showErrorIcon = () => {

518

const errorDiv = document.createElement('div');

519

errorDiv.innerHTML = BROKEN_FILE_SVG_ICON;

520

errorDiv.className = 'widget-error-display';

521

return errorDiv;

522

};

523

```