plug-code 1.2.0 → 2.0.1

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.
Files changed (49) hide show
  1. package/README.md +135 -94
  2. package/dist/core/helpers/core.d.ts +2 -0
  3. package/dist/core/helpers/core.js +32 -0
  4. package/dist/core/hooks/plcHooks.d.ts +15 -0
  5. package/dist/core/hooks/plcHooks.js +47 -0
  6. package/dist/core/plcAPI.d.ts +83 -0
  7. package/dist/core/plcAPI.js +472 -0
  8. package/dist/core/plcPipeline.d.ts +8 -0
  9. package/dist/core/plcPipeline.js +35 -0
  10. package/dist/core/plcScheduler.d.ts +7 -0
  11. package/dist/core/plcScheduler.js +22 -0
  12. package/dist/core/plcStore.d.ts +33 -0
  13. package/dist/core/plcStore.js +159 -0
  14. package/dist/core/ui/plcCore.d.ts +8 -0
  15. package/dist/core/ui/plcCore.js +40 -0
  16. package/dist/core/ui/plcErrorBoundary.d.ts +17 -0
  17. package/dist/core/ui/plcErrorBoundary.js +17 -0
  18. package/dist/core/ui/plcInspector.d.ts +5 -0
  19. package/dist/core/ui/plcInspector.js +27 -0
  20. package/dist/core/ui/plcLayout.d.ts +28 -0
  21. package/dist/core/ui/plcLayout.js +125 -0
  22. package/dist/index.d.ts +8 -0
  23. package/dist/index.js +8 -0
  24. package/dist/types/core/api.d.ts +7 -0
  25. package/dist/types/core/api.js +1 -0
  26. package/dist/types/core/general.d.ts +15 -0
  27. package/dist/types/core/general.js +1 -0
  28. package/dist/types/core/registry.d.ts +7 -0
  29. package/dist/types/core/registry.js +1 -0
  30. package/dist/types/core/ui.d.ts +7 -0
  31. package/dist/types/core/ui.js +1 -0
  32. package/dist/types/registry.d.ts +20 -0
  33. package/dist/types/registry.js +1 -0
  34. package/package.json +16 -22
  35. package/index.d.ts +0 -1
  36. package/src/contexts/pipeline.tsx +0 -4
  37. package/src/core/plcAPI.tsx +0 -393
  38. package/src/core/plcPipeline.tsx +0 -87
  39. package/src/core/plcStore.tsx +0 -94
  40. package/src/helpers/core.ts +0 -10
  41. package/src/plug-code.tsx +0 -64
  42. package/src/types/api.ts +0 -8
  43. package/src/types/features.ts +0 -7
  44. package/src/types/general.ts +0 -2
  45. package/src/types/pipeline.ts +0 -3
  46. package/src/types/registry.ts +0 -4
  47. package/src/types/store.ts +0 -2
  48. package/tsconfig.json +0 -15
  49. package/types/plug-code.d.ts +0 -164
@@ -0,0 +1,472 @@
1
+ import React from "react";
2
+ import { isEqual, shallowCompare } from "./helpers/core";
3
+ import { PlcPipeline } from "./plcPipeline";
4
+ import { LRUCache } from "./plcStore";
5
+ import { Scheduler } from "./plcScheduler";
6
+ import { PlcLayout } from "./ui/plcLayout";
7
+ export class PlcAPI {
8
+ store;
9
+ pipeline;
10
+ scheduler;
11
+ layout;
12
+ compiledPipelines = new Map();
13
+ receiveCache = new LRUCache(300);
14
+ // Comandos registry
15
+ commands = new Map();
16
+ activeDependencyTracker = null;
17
+ // Loaded features manager
18
+ loadedFeatures = new Set();
19
+ constructor(store) {
20
+ this.store = store;
21
+ this.pipeline = new PlcPipeline();
22
+ this.scheduler = new Scheduler();
23
+ this.layout = new PlcLayout();
24
+ }
25
+ // ----------------------
26
+ // Root store
27
+ // ----------------------
28
+ createStore(key, initial) {
29
+ this.store.createStore(key, initial);
30
+ }
31
+ getStore(key) {
32
+ const value = this.store.getStore(key);
33
+ this.recordDependency(key, value);
34
+ return value;
35
+ }
36
+ setStore(key, updater, priority = "MED", useTransition = false) {
37
+ this.scheduler.schedule(() => {
38
+ if (useTransition) {
39
+ React.startTransition(() => {
40
+ this.store.setStore(key, updater);
41
+ });
42
+ }
43
+ else {
44
+ this.store.setStore(key, updater);
45
+ }
46
+ }, priority);
47
+ }
48
+ // ----------------------
49
+ // Substores
50
+ // ----------------------
51
+ createSubstore(substore, key, initial) {
52
+ this.store.createSubstore(substore, key, initial);
53
+ }
54
+ getSubstore(substore, key) {
55
+ const value = this.store.getSubstore(substore, key);
56
+ this.recordDependency(`${substore}:${key}`, value);
57
+ return value;
58
+ }
59
+ setSubstore(substore, key, updater, priority = "MED", useTransition = false) {
60
+ this.scheduler.schedule(() => {
61
+ if (useTransition) {
62
+ React.startTransition(() => {
63
+ this.store.setSubstore(substore, key, updater);
64
+ });
65
+ }
66
+ else {
67
+ this.store.setSubstore(substore, key, updater);
68
+ }
69
+ }, priority);
70
+ }
71
+ // ----------------------
72
+ // Dependency tracking
73
+ // ----------------------
74
+ recordDependency(key, value) {
75
+ if (this.activeDependencyTracker)
76
+ this.activeDependencyTracker.set(key, value);
77
+ }
78
+ // ----------------------
79
+ // Transforms
80
+ // ----------------------
81
+ makeTransform(channel, id, fn, priority = 0) {
82
+ const t = { id, priority, fn: (d, c) => fn(d, c) };
83
+ this.pipeline.registerTransform(channel, t);
84
+ this.compiledPipelines.delete(channel);
85
+ this.receiveCache.delete(channel);
86
+ }
87
+ async getTransform(channel, initialData, context = {}, opts) {
88
+ const channelStr = channel;
89
+ const cached = this.receiveCache.get(channelStr);
90
+ const equality = opts?.equality ?? 'identity';
91
+ if (cached) {
92
+ const sameInput = equality === 'identity' ? cached.input === initialData : isEqual(cached.input, initialData);
93
+ const sameContext = shallowCompare(cached.contextArgs, context);
94
+ if (sameInput && sameContext) {
95
+ let depsChanged = false;
96
+ for (const [key, lastValue] of cached.dependencies) {
97
+ let current;
98
+ if (key.includes(":")) {
99
+ const [substore, subKey] = key.split(":");
100
+ current = this.store.getSubstore(substore, subKey);
101
+ }
102
+ else {
103
+ current = this.store.getStore(key);
104
+ }
105
+ if (current !== lastValue) {
106
+ depsChanged = true;
107
+ break;
108
+ }
109
+ }
110
+ if (!depsChanged)
111
+ return cached.result;
112
+ }
113
+ }
114
+ let runner = this.compiledPipelines.get(channelStr);
115
+ if (!runner) {
116
+ const compiled = this.pipeline.compilePipeline(channelStr);
117
+ this.compiledPipelines.set(channelStr, compiled);
118
+ runner = compiled;
119
+ }
120
+ const prevTracker = this.activeDependencyTracker;
121
+ const currentTracker = new Map();
122
+ this.activeDependencyTracker = currentTracker;
123
+ let result;
124
+ try {
125
+ result = await this.store.runWithDependencyTracker(currentTracker, async () => {
126
+ return await runner(initialData, context);
127
+ });
128
+ }
129
+ finally {
130
+ this.activeDependencyTracker = prevTracker;
131
+ }
132
+ this.receiveCache.set(channelStr, {
133
+ input: initialData,
134
+ result,
135
+ dependencies: currentTracker,
136
+ contextArgs: context
137
+ });
138
+ return result;
139
+ }
140
+ receive(channel, initialData, context = {}) {
141
+ const channelStr = channel;
142
+ const runner = this.compiledPipelines.get(channelStr);
143
+ if (!runner)
144
+ throw new Error("[PlcAPI] Pipeline not compiled yet. Use getTransform (async).");
145
+ const res = runner(initialData, context);
146
+ if (res && typeof res.then === 'function')
147
+ throw new Error("[PlcAPI] Pipeline contains async transforms; use getTransform (async).");
148
+ return res;
149
+ }
150
+ // ----------------------
151
+ // Command System (SOLUCIÓN AQUI)
152
+ // ----------------------
153
+ registerCommand(id, fn) {
154
+ if (this.commands.has(id)) {
155
+ console.warn(`[PlcAPI] Overwriting command '${id}'`);
156
+ }
157
+ this.commands.set(id, fn);
158
+ }
159
+ wrapCommand(id, wrapper) {
160
+ const currentFn = this.commands.get(id);
161
+ if (!currentFn) {
162
+ console.error(`[PlcAPI] Cannot wrap '${id}', command does not exist.`);
163
+ return;
164
+ }
165
+ this.commands.set(id, wrapper(currentFn));
166
+ }
167
+ async execute(id, payload) {
168
+ const fn = this.commands.get(id);
169
+ if (!fn) {
170
+ throw new Error(`[PlcAPI] Command '${id}' not found.`);
171
+ }
172
+ try {
173
+ return await fn(payload);
174
+ }
175
+ catch (error) {
176
+ console.error(`[PlcAPI] Error executing '${id}':`, error);
177
+ throw error;
178
+ }
179
+ }
180
+ // ----------------------
181
+ // Derives
182
+ // ----------------------
183
+ deriveStore(outputKey, outputSlot, dependencies, calculator) {
184
+ let lastInputs = null;
185
+ let lastOutput;
186
+ let isComputing = false;
187
+ let scheduled = false;
188
+ const scheduleUpdate = () => {
189
+ if (scheduled)
190
+ return;
191
+ scheduled = true;
192
+ Promise.resolve().then(() => {
193
+ scheduled = false;
194
+ this.store.batch(runCompute);
195
+ });
196
+ };
197
+ const runCompute = () => {
198
+ if (isComputing)
199
+ return;
200
+ isComputing = true;
201
+ try {
202
+ const inputs = dependencies.map(dep => this.getStore(dep));
203
+ if (lastInputs && inputs.every((v, i) => isEqual(v, lastInputs[i])))
204
+ return;
205
+ const result = calculator(...inputs);
206
+ if (isEqual(result, lastOutput)) {
207
+ lastInputs = inputs;
208
+ return;
209
+ }
210
+ lastInputs = inputs;
211
+ lastOutput = result;
212
+ this.setStore(outputSlot, (draft) => {
213
+ if (!draft)
214
+ return { [String(outputKey)]: result };
215
+ draft[String(outputKey)] = result;
216
+ return;
217
+ });
218
+ }
219
+ finally {
220
+ isComputing = false;
221
+ }
222
+ };
223
+ runCompute();
224
+ const unsubscribers = dependencies.map(dep => this.store.subscribe(dep, scheduleUpdate));
225
+ return {
226
+ getValue: () => lastOutput,
227
+ trigger: scheduleUpdate,
228
+ dispose: () => unsubscribers.forEach(u => u())
229
+ };
230
+ }
231
+ deriveSubstore(substore, outputKey, outputSlot, dependencies, calculator) {
232
+ let lastInputs = null;
233
+ let lastOutput;
234
+ let isComputing = false;
235
+ let scheduled = false;
236
+ const scheduleUpdate = () => {
237
+ if (scheduled)
238
+ return;
239
+ scheduled = true;
240
+ Promise.resolve().then(() => {
241
+ scheduled = false;
242
+ this.store.batch(runCompute);
243
+ });
244
+ };
245
+ const runCompute = () => {
246
+ if (isComputing)
247
+ return;
248
+ isComputing = true;
249
+ try {
250
+ const inputs = dependencies.map(dep => this.getSubstore(substore, dep));
251
+ if (lastInputs && inputs.every((v, i) => isEqual(v, lastInputs[i])))
252
+ return;
253
+ const result = calculator(...inputs);
254
+ if (isEqual(result, lastOutput)) {
255
+ lastInputs = inputs;
256
+ return;
257
+ }
258
+ lastInputs = inputs;
259
+ lastOutput = result;
260
+ this.setSubstore(substore, outputSlot, (draft) => {
261
+ if (!draft)
262
+ return { [String(outputKey)]: result };
263
+ draft[String(outputKey)] = result;
264
+ return;
265
+ });
266
+ }
267
+ finally {
268
+ isComputing = false;
269
+ }
270
+ };
271
+ runCompute();
272
+ const unsubscribers = dependencies.map(dep => this.store.subscribe(`${substore}:${dep}`, scheduleUpdate));
273
+ return {
274
+ getValue: () => lastOutput,
275
+ trigger: scheduleUpdate,
276
+ dispose: () => unsubscribers.forEach(u => u())
277
+ };
278
+ }
279
+ // ----------------------
280
+ // Watchers
281
+ // ----------------------
282
+ _triggerVersion = new Map();
283
+ bumpVersion(key) {
284
+ this._triggerVersion.set(key, (this._triggerVersion.get(key) || 0) + 1);
285
+ }
286
+ watch(key, selector, callback) {
287
+ if (key.includes(":")) {
288
+ const [feature, subKey] = key.split(":");
289
+ return this.watchSubstore(feature, subKey, selector, callback);
290
+ }
291
+ return this.watchStore(key, selector, callback);
292
+ }
293
+ watchStore(storeKey, selector, callback) {
294
+ let prevVersion = this._triggerVersion.get(storeKey) || 0;
295
+ let prevValue = selector(this.getStore(storeKey));
296
+ const handleChange = () => {
297
+ const version = this._triggerVersion.get(storeKey) || 0;
298
+ const newValue = selector(this.getStore(storeKey));
299
+ if (version !== prevVersion || !isEqual(newValue, prevValue)) {
300
+ const old = prevValue;
301
+ prevValue = newValue;
302
+ prevVersion = version;
303
+ callback(newValue, old);
304
+ }
305
+ };
306
+ return this.store.subscribe(storeKey, handleChange);
307
+ }
308
+ watchSubstore(substore, key, selector, callback) {
309
+ const storeKey = `${substore}:${key}`;
310
+ let prevVersion = this._triggerVersion.get(storeKey) || 0;
311
+ let prevValue = selector(this.getSubstore(substore, key));
312
+ const handleChange = () => {
313
+ const version = this._triggerVersion.get(storeKey) || 0;
314
+ const newValue = selector(this.getSubstore(substore, key));
315
+ if (version !== prevVersion || !isEqual(newValue, prevValue)) {
316
+ const old = prevValue;
317
+ prevValue = newValue;
318
+ prevVersion = version;
319
+ callback(newValue, old);
320
+ }
321
+ };
322
+ return this.store.subscribe(storeKey, handleChange);
323
+ }
324
+ watchAllStores(definitions, callback) {
325
+ const getCombinedState = () => {
326
+ let result = {};
327
+ for (const def of definitions) {
328
+ const slice = def.substore
329
+ ? def.selector(this.getSubstore(def.substore, def.store))
330
+ : def.selector(this.getStore(def.store));
331
+ result = { ...result, ...slice };
332
+ }
333
+ return result;
334
+ };
335
+ let prevCombined = getCombinedState();
336
+ const handleChange = () => {
337
+ const currentCombined = getCombinedState();
338
+ if (!isEqual(prevCombined, currentCombined)) {
339
+ const old = prevCombined;
340
+ prevCombined = currentCombined;
341
+ callback(currentCombined, old);
342
+ }
343
+ };
344
+ const unsubscribers = definitions.map(def => {
345
+ const key = def.substore ? `${def.substore}:${def.store}` : def.store;
346
+ return this.store.subscribe(key, handleChange);
347
+ });
348
+ return () => unsubscribers.forEach(u => u());
349
+ }
350
+ // ----------------------
351
+ // Redraw
352
+ // ----------------------
353
+ redraw(keyOrSlot) {
354
+ this.bumpVersion(keyOrSlot);
355
+ this.layout.invalidate(keyOrSlot);
356
+ const currentRoot = this.store.getStore(keyOrSlot);
357
+ if (currentRoot !== undefined) {
358
+ this.store.setStore(keyOrSlot, (d) => d);
359
+ }
360
+ }
361
+ // ----------------------
362
+ // UI
363
+ // ----------------------
364
+ register(slot, id, componentFn, priority = 0, keepAlive = false) {
365
+ this.layout.register(slot, id, componentFn, priority, keepAlive);
366
+ }
367
+ wrap(slot, wrapper) {
368
+ this.layout.wrap(slot, wrapper);
369
+ }
370
+ after(slot, targetId, newId, componentFn) {
371
+ const targetPriority = this.layout.getPriority(slot, targetId);
372
+ let newPriority;
373
+ if (targetPriority !== undefined) {
374
+ newPriority = targetPriority - 1;
375
+ }
376
+ else {
377
+ console.warn(`[PlcAPI] 'after': Target '${targetId}' not found in slot '${slot}'. Registering '${newId}' at the end.`);
378
+ newPriority = -999;
379
+ }
380
+ this.layout.register(slot, newId, componentFn, newPriority);
381
+ }
382
+ render(slot, props) {
383
+ return this.layout.render(slot, props);
384
+ }
385
+ markVirtual(slot, config) {
386
+ this.layout.markVirtual(slot, config);
387
+ }
388
+ connect(renderFn, dependencies) {
389
+ return (props) => {
390
+ const [, forceUpdate] = React.useReducer(x => x + 1, 0);
391
+ const prevValuesRef = React.useRef(new Map());
392
+ React.useEffect(() => {
393
+ const unsubscribers = [];
394
+ dependencies.forEach(dep => {
395
+ const keyStr = typeof dep === 'string' ? dep : dep.store;
396
+ const getValue = () => typeof dep === 'string'
397
+ ? this.getStore(dep)
398
+ : dep.store.includes(":")
399
+ ? this.store.getSubstore(...dep.store.split(":"))
400
+ : this.getStore(dep.store);
401
+ prevValuesRef.current.set(keyStr, getValue());
402
+ unsubscribers.push(this.store.subscribe(keyStr, () => {
403
+ const newVal = getValue();
404
+ if (!isEqual(prevValuesRef.current.get(keyStr), newVal)) {
405
+ prevValuesRef.current.set(keyStr, newVal);
406
+ forceUpdate();
407
+ }
408
+ }));
409
+ });
410
+ return () => unsubscribers.forEach(u => u());
411
+ }, []);
412
+ return renderFn(props);
413
+ };
414
+ }
415
+ // ----------------------
416
+ // Modules
417
+ // ----------------------
418
+ registerModule(manifest) {
419
+ if (this.loadedFeatures.has(manifest.name))
420
+ return;
421
+ if (manifest.state) {
422
+ Object.entries(manifest.state).forEach(([key, val]) => {
423
+ this.createSubstore(manifest.name, key, val);
424
+ });
425
+ }
426
+ if (manifest.commands) {
427
+ Object.entries(manifest.commands).forEach(([cmdId, fn]) => {
428
+ const fullId = cmdId.includes(":") ? cmdId : `${manifest.name}:${cmdId}`;
429
+ this.commands.set(fullId, fn);
430
+ });
431
+ }
432
+ if (manifest.slots) {
433
+ Object.entries(manifest.slots).forEach(([slotName, components]) => {
434
+ components.forEach(comp => {
435
+ this.register(slotName, comp.id, comp.component, comp.priority, comp.keepAlive);
436
+ });
437
+ });
438
+ }
439
+ if (manifest.onLoad) {
440
+ manifest.onLoad(this);
441
+ }
442
+ this.loadedFeatures.add(manifest.name);
443
+ console.debug(`[PlcAPI] Feature loaded: ${manifest.name}`);
444
+ }
445
+ async loadFeature(importer) {
446
+ try {
447
+ const module = await importer();
448
+ this.registerModule(module.default);
449
+ }
450
+ catch (err) {
451
+ console.error(`[PlcAPI] Failed to load feature`, err);
452
+ throw err;
453
+ }
454
+ }
455
+ // ----------------------
456
+ // Selector
457
+ // ----------------------
458
+ createSelector(extractor, calculator) {
459
+ let lastArgs = null;
460
+ let lastResult = null;
461
+ return (state) => {
462
+ const args = extractor(state);
463
+ if (lastArgs && args.length === lastArgs.length && args.every((val, i) => val === lastArgs[i])) {
464
+ return lastResult;
465
+ }
466
+ const result = calculator(...args);
467
+ lastArgs = args;
468
+ lastResult = result;
469
+ return result;
470
+ };
471
+ }
472
+ }
@@ -0,0 +1,8 @@
1
+ import { transformerType } from "../types/core/api";
2
+ export declare class PlcPipeline {
3
+ private transforms;
4
+ registerTransform(channel: string, t: transformerType): void;
5
+ removeTransform(channel: string, id: string): void;
6
+ getTransforms(channel: string): transformerType[];
7
+ compilePipeline(channel: string): (input: any, ctx: any) => Promise<any>;
8
+ }
@@ -0,0 +1,35 @@
1
+ export class PlcPipeline {
2
+ transforms = new Map();
3
+ registerTransform(channel, t) {
4
+ if (!this.transforms.has(channel))
5
+ this.transforms.set(channel, []);
6
+ const list = this.transforms.get(channel);
7
+ const idx = list.findIndex(x => x.id === t.id);
8
+ if (idx >= 0)
9
+ list[idx] = t;
10
+ else
11
+ list.push(t);
12
+ list.sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0));
13
+ }
14
+ removeTransform(channel, id) {
15
+ const list = this.transforms.get(channel);
16
+ if (!list)
17
+ return;
18
+ const idx = list.findIndex(x => x.id === id);
19
+ if (idx >= 0)
20
+ list.splice(idx, 1);
21
+ }
22
+ getTransforms(channel) {
23
+ return this.transforms.get(channel) || [];
24
+ }
25
+ compilePipeline(channel) {
26
+ const list = this.getTransforms(channel);
27
+ return async (input, ctx) => {
28
+ let data = input;
29
+ for (const t of list) {
30
+ data = await t.fn(data, ctx);
31
+ }
32
+ return data;
33
+ };
34
+ }
35
+ }
@@ -0,0 +1,7 @@
1
+ export type Priority = "HIGH" | "MED" | "LOW";
2
+ export declare class Scheduler {
3
+ private isFlushing;
4
+ private queue;
5
+ schedule(fn: () => void, priority?: Priority): void;
6
+ private flush;
7
+ }
@@ -0,0 +1,22 @@
1
+ export class Scheduler {
2
+ isFlushing = false;
3
+ queue = new Map([
4
+ ["HIGH", new Set()],
5
+ ["MED", new Set()],
6
+ ["LOW", new Set()],
7
+ ]);
8
+ schedule(fn, priority = "MED") {
9
+ this.queue.get(priority).add(fn);
10
+ if (!this.isFlushing)
11
+ this.flush();
12
+ }
13
+ flush() {
14
+ this.isFlushing = true;
15
+ for (const level of ["HIGH", "MED", "LOW"]) {
16
+ const set = this.queue.get(level);
17
+ set.forEach(fn => fn());
18
+ set.clear();
19
+ }
20
+ this.isFlushing = false;
21
+ }
22
+ }
@@ -0,0 +1,33 @@
1
+ import { Draft } from "immer";
2
+ export type Listener = () => void;
3
+ export type keyListenerMap = Map<string, Set<Listener>>;
4
+ export declare class PlcStore {
5
+ private storeData;
6
+ private substoresData;
7
+ private subscriptions;
8
+ private isBatching;
9
+ private dirtyKeys;
10
+ private activeDependencyTracker;
11
+ createStore<K extends string, T>(key: K, initial: T): void;
12
+ getStore(key: string): any;
13
+ setStore<T>(key: string, updater: T | ((draft: Draft<T>) => void | T)): void;
14
+ createSubstore<K extends string, T>(substore: string, key: K, initial: T): void;
15
+ getSubstore(substore: string, key: string): any;
16
+ setSubstore<T>(substore: string, key: string, updater: T | ((draft: Draft<T>) => void | T)): void;
17
+ protected recordDependency(key: string, value: any): void;
18
+ runWithDependencyTracker<T>(tracker: Map<string, any> | null, fn: () => T | Promise<T>): Promise<T>;
19
+ batch(fn: () => void): void;
20
+ subscribe(key: string, listener: Listener): () => void;
21
+ private markDirty;
22
+ private flush;
23
+ private notify;
24
+ }
25
+ export declare class LRUCache<K, V> {
26
+ private maxEntries;
27
+ private map;
28
+ constructor(maxEntries?: number);
29
+ get(key: K): V | undefined;
30
+ set(key: K, value: V): void;
31
+ delete(key: K): void;
32
+ clear(): void;
33
+ }