@platforma-sdk/model 1.57.2 → 1.58.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 (94) hide show
  1. package/dist/block_migrations.cjs +60 -77
  2. package/dist/block_migrations.cjs.map +1 -1
  3. package/dist/block_migrations.d.ts +35 -32
  4. package/dist/block_migrations.d.ts.map +1 -1
  5. package/dist/block_migrations.js +60 -78
  6. package/dist/block_migrations.js.map +1 -1
  7. package/dist/block_model.cjs +18 -14
  8. package/dist/block_model.cjs.map +1 -1
  9. package/dist/block_model.d.ts +5 -5
  10. package/dist/block_model.d.ts.map +1 -1
  11. package/dist/block_model.js +18 -14
  12. package/dist/block_model.js.map +1 -1
  13. package/dist/block_model_legacy.cjs +1 -0
  14. package/dist/block_model_legacy.cjs.map +1 -1
  15. package/dist/block_model_legacy.d.ts.map +1 -1
  16. package/dist/block_model_legacy.js +1 -0
  17. package/dist/block_model_legacy.js.map +1 -1
  18. package/dist/block_storage.cjs +24 -20
  19. package/dist/block_storage.cjs.map +1 -1
  20. package/dist/block_storage.d.ts +20 -16
  21. package/dist/block_storage.d.ts.map +1 -1
  22. package/dist/block_storage.js +24 -20
  23. package/dist/block_storage.js.map +1 -1
  24. package/dist/block_storage_callbacks.cjs +4 -3
  25. package/dist/block_storage_callbacks.cjs.map +1 -1
  26. package/dist/block_storage_callbacks.d.ts +7 -5
  27. package/dist/block_storage_callbacks.d.ts.map +1 -1
  28. package/dist/block_storage_callbacks.js +4 -3
  29. package/dist/block_storage_callbacks.js.map +1 -1
  30. package/dist/components/PFrameForGraphs.cjs +0 -117
  31. package/dist/components/PFrameForGraphs.cjs.map +1 -1
  32. package/dist/components/PFrameForGraphs.d.ts +3 -5
  33. package/dist/components/PFrameForGraphs.d.ts.map +1 -1
  34. package/dist/components/PFrameForGraphs.js +2 -117
  35. package/dist/components/PFrameForGraphs.js.map +1 -1
  36. package/dist/index.cjs +8 -5
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.ts +4 -3
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +5 -3
  41. package/dist/index.js.map +1 -1
  42. package/dist/package.json.cjs +1 -1
  43. package/dist/package.json.js +1 -1
  44. package/dist/pframe_utils/axes.cjs +131 -0
  45. package/dist/pframe_utils/axes.cjs.map +1 -0
  46. package/dist/pframe_utils/axes.d.ts +15 -0
  47. package/dist/pframe_utils/axes.d.ts.map +1 -0
  48. package/dist/pframe_utils/axes.js +128 -0
  49. package/dist/pframe_utils/axes.js.map +1 -0
  50. package/dist/pframe_utils/columns.cjs +4 -8
  51. package/dist/pframe_utils/columns.cjs.map +1 -1
  52. package/dist/pframe_utils/columns.js +1 -5
  53. package/dist/pframe_utils/columns.js.map +1 -1
  54. package/dist/pframe_utils/index.cjs +0 -3
  55. package/dist/pframe_utils/index.cjs.map +1 -1
  56. package/dist/pframe_utils/index.js +0 -3
  57. package/dist/pframe_utils/index.js.map +1 -1
  58. package/dist/platforma.d.ts +12 -2
  59. package/dist/platforma.d.ts.map +1 -1
  60. package/dist/plugin_handle.cjs +29 -0
  61. package/dist/plugin_handle.cjs.map +1 -0
  62. package/dist/plugin_handle.d.ts +51 -0
  63. package/dist/plugin_handle.d.ts.map +1 -0
  64. package/dist/plugin_handle.js +25 -0
  65. package/dist/plugin_handle.js.map +1 -0
  66. package/dist/plugin_model.cjs +29 -29
  67. package/dist/plugin_model.cjs.map +1 -1
  68. package/dist/plugin_model.d.ts +43 -35
  69. package/dist/plugin_model.d.ts.map +1 -1
  70. package/dist/plugin_model.js +29 -29
  71. package/dist/plugin_model.js.map +1 -1
  72. package/dist/render/api.cjs +9 -5
  73. package/dist/render/api.cjs.map +1 -1
  74. package/dist/render/api.d.ts +11 -5
  75. package/dist/render/api.d.ts.map +1 -1
  76. package/dist/render/api.js +9 -5
  77. package/dist/render/api.js.map +1 -1
  78. package/package.json +6 -6
  79. package/src/block_migrations.test.ts +109 -12
  80. package/src/block_migrations.ts +63 -87
  81. package/src/block_model.ts +34 -20
  82. package/src/block_model_legacy.ts +1 -0
  83. package/src/block_storage.test.ts +11 -10
  84. package/src/block_storage.ts +40 -32
  85. package/src/block_storage_callbacks.ts +12 -10
  86. package/src/components/PFrameForGraphs.ts +4 -167
  87. package/src/index.ts +24 -2
  88. package/src/pframe_utils/axes.ts +175 -0
  89. package/src/pframe_utils/columns.ts +2 -2
  90. package/src/platforma.ts +17 -2
  91. package/src/plugin_handle.ts +85 -0
  92. package/src/plugin_model.test.ts +2 -2
  93. package/src/plugin_model.ts +120 -58
  94. package/src/render/api.ts +21 -11
@@ -452,6 +452,7 @@ export class BlockModel<
452
452
  },
453
453
  ]),
454
454
  ),
455
+ pluginIds: [],
455
456
  },
456
457
  };
457
458
  }
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
2
2
  import {
3
3
  BLOCK_STORAGE_KEY,
4
4
  BLOCK_STORAGE_SCHEMA_VERSION,
5
- DATA_MODEL_DEFAULT_VERSION,
5
+ DATA_MODEL_LEGACY_VERSION,
6
6
  createBlockStorage,
7
7
  getPluginData,
8
8
  getStorageData,
@@ -14,6 +14,7 @@ import {
14
14
  type PluginName,
15
15
  type PluginRegistry,
16
16
  } from "./block_storage";
17
+ import type { PluginHandle } from "./plugin_handle";
17
18
 
18
19
  describe("BlockStorage", () => {
19
20
  describe("BLOCK_STORAGE_KEY and BLOCK_STORAGE_SCHEMA_VERSION", () => {
@@ -71,7 +72,7 @@ describe("BlockStorage", () => {
71
72
  it("should create storage with discriminator key and default values", () => {
72
73
  const storage = createBlockStorage();
73
74
  expect(storage[BLOCK_STORAGE_KEY]).toBe(BLOCK_STORAGE_SCHEMA_VERSION);
74
- expect(storage.__dataVersion).toBe(DATA_MODEL_DEFAULT_VERSION);
75
+ expect(storage.__dataVersion).toBe(DATA_MODEL_LEGACY_VERSION);
75
76
  expect(storage.__data).toEqual({});
76
77
  });
77
78
 
@@ -79,7 +80,7 @@ describe("BlockStorage", () => {
79
80
  const data = { numbers: [1, 2, 3] };
80
81
  const storage = createBlockStorage(data);
81
82
  expect(storage[BLOCK_STORAGE_KEY]).toBe(BLOCK_STORAGE_SCHEMA_VERSION);
82
- expect(storage.__dataVersion).toBe(DATA_MODEL_DEFAULT_VERSION);
83
+ expect(storage.__dataVersion).toBe(DATA_MODEL_LEGACY_VERSION);
83
84
  expect(storage.__data).toEqual(data);
84
85
  });
85
86
 
@@ -135,7 +136,7 @@ describe("BlockStorage", () => {
135
136
  const legacyData = { numbers: [1, 2, 3], name: "test" };
136
137
  const normalized = normalizeBlockStorage(legacyData);
137
138
  expect(normalized[BLOCK_STORAGE_KEY]).toBe(BLOCK_STORAGE_SCHEMA_VERSION);
138
- expect(normalized.__dataVersion).toBe(DATA_MODEL_DEFAULT_VERSION);
139
+ expect(normalized.__dataVersion).toBe(DATA_MODEL_LEGACY_VERSION);
139
140
  expect(normalized.__data).toEqual(legacyData);
140
141
  expect(normalized.__pluginRegistry).toEqual({});
141
142
  expect(normalized.__plugins).toEqual({});
@@ -144,14 +145,14 @@ describe("BlockStorage", () => {
144
145
  it("should wrap primitive legacy data", () => {
145
146
  const normalized = normalizeBlockStorage("simple string");
146
147
  expect(normalized[BLOCK_STORAGE_KEY]).toBe(BLOCK_STORAGE_SCHEMA_VERSION);
147
- expect(normalized.__dataVersion).toBe(DATA_MODEL_DEFAULT_VERSION);
148
+ expect(normalized.__dataVersion).toBe(DATA_MODEL_LEGACY_VERSION);
148
149
  expect(normalized.__data).toBe("simple string");
149
150
  });
150
151
 
151
152
  it("should wrap null legacy data", () => {
152
153
  const normalized = normalizeBlockStorage(null);
153
154
  expect(normalized[BLOCK_STORAGE_KEY]).toBe(BLOCK_STORAGE_SCHEMA_VERSION);
154
- expect(normalized.__dataVersion).toBe(DATA_MODEL_DEFAULT_VERSION);
155
+ expect(normalized.__dataVersion).toBe(DATA_MODEL_LEGACY_VERSION);
155
156
  expect(normalized.__data).toBeNull();
156
157
  });
157
158
  });
@@ -187,7 +188,7 @@ describe("BlockStorage", () => {
187
188
  });
188
189
  expect(storage.__plugins).toEqual({
189
190
  table1: {
190
- __dataVersion: DATA_MODEL_DEFAULT_VERSION,
191
+ __dataVersion: DATA_MODEL_LEGACY_VERSION,
191
192
  __data: { columns: ["a", "b"] },
192
193
  },
193
194
  });
@@ -215,11 +216,11 @@ describe("BlockStorage", () => {
215
216
  pluginId: "chart1",
216
217
  value: { type: "bar" },
217
218
  });
218
- expect(getPluginData(storage, "chart1")).toEqual({ type: "bar" });
219
+ expect(getPluginData(storage, "chart1" as PluginHandle)).toEqual({ type: "bar" });
219
220
  });
220
221
 
221
222
  it("getPluginData should throw for missing plugin", () => {
222
- expect(() => getPluginData(baseStorage, "nonexistent")).toThrow(
223
+ expect(() => getPluginData(baseStorage, "nonexistent" as PluginHandle)).toThrow(
223
224
  "Plugin 'nonexistent' not found in block storage",
224
225
  );
225
226
  });
@@ -253,7 +254,7 @@ describe("BlockStorage", () => {
253
254
  value: { foo: "bar" },
254
255
  });
255
256
  expect(updated.__plugins?.plugin1).toEqual({
256
- __dataVersion: DATA_MODEL_DEFAULT_VERSION,
257
+ __dataVersion: DATA_MODEL_LEGACY_VERSION,
257
258
  __data: { foo: "bar" },
258
259
  });
259
260
  });
@@ -10,7 +10,8 @@
10
10
  */
11
11
 
12
12
  import type { Branded } from "@milaboratories/pl-model-common";
13
- import type { DataMigrationResult, DataVersioned } from "./block_migrations";
13
+ import type { DataVersioned } from "./block_migrations";
14
+ import type { PluginHandle, PluginFactoryLike, InferFactoryData } from "./plugin_handle";
14
15
 
15
16
  // =============================================================================
16
17
  // Core Types
@@ -32,7 +33,7 @@ export const BLOCK_STORAGE_SCHEMA_VERSION = "v1";
32
33
  * Default data version for new blocks without migrations.
33
34
  * Unique identifier ensures blocks are created via DataModel API.
34
35
  */
35
- export const DATA_MODEL_DEFAULT_VERSION = "__pl_v1_d4e8f2a1__";
36
+ export const DATA_MODEL_LEGACY_VERSION = "__pl_v1_d4e8f2a1__";
36
37
 
37
38
  /**
38
39
  * Type for valid schema versions
@@ -50,7 +51,7 @@ export type PluginName = Branded<string, "PluginName">;
50
51
  * Plugin registry - maps pluginId (unique within a block) to pluginName (globally unique plugin type).
51
52
  * Using a Record highlights that pluginIds must be unique within a block.
52
53
  */
53
- export type PluginRegistry = Record<string, PluginName>;
54
+ export type PluginRegistry = Record<PluginHandle, PluginName>;
54
55
 
55
56
  /**
56
57
  * Versioned data - used for both block data and plugin data
@@ -75,8 +76,8 @@ export type BlockStorage<TState = unknown> = {
75
76
  readonly [BLOCK_STORAGE_KEY]: BlockStorageSchemaVersion;
76
77
  /** Registry of plugins: pluginId -> pluginName */
77
78
  __pluginRegistry?: PluginRegistry;
78
- /** Plugin-specific data, keyed by pluginId */
79
- __plugins?: Record<string, VersionedData<unknown>>;
79
+ /** Plugin-specific data, keyed by plugin handle */
80
+ __plugins?: Record<PluginHandle, VersionedData<unknown>>;
80
81
  } & VersionedData<TState>;
81
82
 
82
83
  /**
@@ -99,12 +100,12 @@ export function isBlockStorage(value: unknown): value is BlockStorage {
99
100
  * Creates a BlockStorage with the given initial data
100
101
  *
101
102
  * @param initialData - The initial data value (defaults to empty object)
102
- * @param version - The initial data version key (defaults to DATA_MODEL_DEFAULT_VERSION)
103
+ * @param version - The initial data version key (defaults to DATA_MODEL_LEGACY_VERSION)
103
104
  * @returns A new BlockStorage instance with discriminator key
104
105
  */
105
106
  export function createBlockStorage<TState = unknown>(
106
107
  initialData: TState = {} as TState,
107
- version: string = DATA_MODEL_DEFAULT_VERSION,
108
+ version: string = DATA_MODEL_LEGACY_VERSION,
108
109
  ): BlockStorage<TState> {
109
110
  return {
110
111
  [BLOCK_STORAGE_KEY]: BLOCK_STORAGE_SCHEMA_VERSION,
@@ -131,7 +132,7 @@ export function normalizeBlockStorage<TState = unknown>(raw: unknown): BlockStor
131
132
  // Fix for early released version where __dataVersion was a number
132
133
  __dataVersion:
133
134
  typeof storage.__dataVersion === "number"
134
- ? DATA_MODEL_DEFAULT_VERSION
135
+ ? DATA_MODEL_LEGACY_VERSION
135
136
  : storage.__dataVersion,
136
137
  // Ensure plugin fields have defaults
137
138
  __pluginRegistry: storage.__pluginRegistry ?? {},
@@ -176,7 +177,7 @@ export function deriveDataFromStorage<TData = unknown>(rawStorage: unknown): TDa
176
177
  /** Payload for storage mutation operations. SDK defines specific operations. */
177
178
  export type MutateStoragePayload<T = unknown> =
178
179
  | { operation: "update-block-data"; value: T }
179
- | { operation: "update-plugin-data"; pluginId: string; value: unknown };
180
+ | { operation: "update-plugin-data"; pluginId: PluginHandle; value: unknown };
180
181
 
181
182
  /**
182
183
  * Updates the data in BlockStorage (immutable)
@@ -196,7 +197,7 @@ export function updateStorageData<TValue = unknown>(
196
197
  const { pluginId, value } = payload;
197
198
  const currentPlugins = storage.__plugins ?? {};
198
199
  const existingEntry = currentPlugins[pluginId];
199
- const version = existingEntry?.__dataVersion ?? DATA_MODEL_DEFAULT_VERSION;
200
+ const version = existingEntry?.__dataVersion ?? DATA_MODEL_LEGACY_VERSION;
200
201
  return {
201
202
  ...storage,
202
203
  __plugins: {
@@ -257,17 +258,17 @@ export type MigrationResult<TState> = MigrationSuccess<TState> | MigrationFailur
257
258
  * Conversion to internal VersionedData format is handled by migrateBlockStorage().
258
259
  */
259
260
  export interface MigrateBlockStorageConfig {
260
- /** Migrate block data from any version to latest */
261
- migrateBlockData: (versioned: DataVersioned<unknown>) => DataMigrationResult<unknown>;
262
- /** Migrate each plugin's data. Return undefined to remove the plugin. */
261
+ /** Migrate block data from any version to latest. Throws on failure. */
262
+ migrateBlockData: (versioned: DataVersioned<unknown>) => DataVersioned<unknown>;
263
+ /** Migrate each plugin's data. Return undefined to remove the plugin. Throws on failure. */
263
264
  migratePluginData: (
264
- pluginId: string,
265
+ handle: PluginHandle,
265
266
  versioned: DataVersioned<unknown>,
266
- ) => DataMigrationResult<unknown> | undefined;
267
+ ) => DataVersioned<unknown> | undefined;
267
268
  /** The new plugin registry after migration (pluginId -> pluginName) */
268
269
  newPluginRegistry: PluginRegistry;
269
270
  /** Factory to create initial data for new plugins */
270
- createPluginData: (pluginId: string) => DataVersioned<unknown>;
271
+ createPluginData: (handle: PluginHandle) => DataVersioned<unknown>;
271
272
  }
272
273
 
273
274
  /**
@@ -334,33 +335,34 @@ export function migrateBlockStorage(
334
335
  // Step 2: Migrate plugins
335
336
  const oldPlugins = storage.__plugins ?? {};
336
337
  const oldRegistry = storage.__pluginRegistry ?? {};
337
- const newPlugins: Record<string, VersionedData<unknown>> = {};
338
+ const newPlugins: Record<PluginHandle, VersionedData<unknown>> = {};
338
339
 
339
- for (const [pluginId, pluginName] of Object.entries(newPluginRegistry)) {
340
- const existingEntry = oldPlugins[pluginId];
341
- const existingName = oldRegistry[pluginId];
340
+ for (const [key, pluginName] of Object.entries(newPluginRegistry)) {
341
+ const handle = key as PluginHandle;
342
+ const existingEntry = oldPlugins[handle];
343
+ const existingName = oldRegistry[handle];
342
344
 
343
345
  try {
344
346
  if (existingEntry && existingName === pluginName) {
345
347
  // Plugin exists with same type - migrate its data
346
- const migrated = migratePluginData(pluginId, {
348
+ const migrated = migratePluginData(handle, {
347
349
  version: existingEntry.__dataVersion,
348
350
  data: existingEntry.__data,
349
351
  });
350
352
  if (migrated) {
351
- newPlugins[pluginId] = { __dataVersion: migrated.version, __data: migrated.data };
353
+ newPlugins[handle] = { __dataVersion: migrated.version, __data: migrated.data };
352
354
  }
353
355
  // If undefined returned, plugin is intentionally removed
354
356
  } else {
355
357
  // New plugin or type changed - create with initial data
356
- const initial = createPluginData(pluginId);
357
- newPlugins[pluginId] = { __dataVersion: initial.version, __data: initial.data };
358
+ const initial = createPluginData(handle);
359
+ newPlugins[handle] = { __dataVersion: initial.version, __data: initial.data };
358
360
  }
359
361
  } catch (error) {
360
362
  return {
361
363
  success: false,
362
364
  error: error instanceof Error ? error.message : String(error),
363
- failedAt: pluginId,
365
+ failedAt: handle,
364
366
  };
365
367
  }
366
368
  }
@@ -384,14 +386,20 @@ export function migrateBlockStorage(
384
386
  * Gets plugin-specific data from block storage.
385
387
  * Accepts raw storage (any format) and normalizes internally.
386
388
  *
389
+ * When called with a typed PluginHandle<F>, the return type is automatically
390
+ * inferred from the factory's phantom `__types.data` field.
391
+ *
387
392
  * @param rawStorage - Raw block storage (may be legacy format or BlockStorage)
388
- * @param pluginId - The plugin instance id
389
- * @returns The plugin data
390
- * @throws If pluginId is not found in storage
393
+ * @param handle - The plugin handle (branded plugin instance id)
394
+ * @returns The plugin data, typed via factory inference
395
+ * @throws If plugin is not found in storage
391
396
  */
392
- export function getPluginData<TData = unknown>(rawStorage: unknown, pluginId: string): TData {
397
+ export function getPluginData<F extends PluginFactoryLike>(
398
+ rawStorage: unknown,
399
+ handle: PluginHandle<F>,
400
+ ): InferFactoryData<F> {
393
401
  const storage = normalizeBlockStorage(rawStorage);
394
- const pluginEntry = storage.__plugins?.[pluginId];
395
- if (!pluginEntry) throw new Error(`Plugin '${pluginId}' not found in block storage`);
396
- return pluginEntry.__data as TData;
402
+ const pluginEntry = storage.__plugins?.[handle];
403
+ if (!pluginEntry) throw new Error(`Plugin '${handle}' not found in block storage`);
404
+ return pluginEntry.__data as InferFactoryData<F>;
397
405
  }
@@ -24,9 +24,10 @@ import {
24
24
  normalizeBlockStorage,
25
25
  updateStorageData,
26
26
  } from "./block_storage";
27
+ import type { PluginHandle } from "./plugin_handle";
27
28
 
28
29
  import { stringifyJson, type StringifiedJson } from "@milaboratories/pl-model-common";
29
- import type { DataMigrationResult, DataVersioned } from "./block_migrations";
30
+ import type { DataVersioned } from "./block_migrations";
30
31
 
31
32
  // =============================================================================
32
33
  // Hook interfaces for dependency injection
@@ -34,20 +35,20 @@ import type { DataMigrationResult, DataVersioned } from "./block_migrations";
34
35
 
35
36
  /** Dependencies for storage migration */
36
37
  export interface MigrationHooks {
37
- migrateBlockData: (versioned: DataVersioned<unknown>) => DataMigrationResult<unknown>;
38
+ migrateBlockData: (versioned: DataVersioned<unknown>) => DataVersioned<unknown>;
38
39
  getPluginRegistry: () => PluginRegistry;
39
40
  migratePluginData: (
40
- pluginId: string,
41
+ handle: PluginHandle,
41
42
  versioned: DataVersioned<unknown>,
42
- ) => DataMigrationResult<unknown> | undefined;
43
- createPluginData: (pluginId: string) => DataVersioned<unknown>;
43
+ ) => DataVersioned<unknown> | undefined;
44
+ createPluginData: (handle: PluginHandle) => DataVersioned<unknown>;
44
45
  }
45
46
 
46
47
  /** Dependencies for initial storage creation */
47
48
  export interface InitialStorageHooks {
48
49
  getDefaultBlockData: () => DataVersioned<unknown>;
49
50
  getPluginRegistry: () => PluginRegistry;
50
- createPluginData: (pluginId: string) => DataVersioned<unknown>;
51
+ createPluginData: (handle: PluginHandle) => DataVersioned<unknown>;
51
52
  }
52
53
 
53
54
  /**
@@ -228,15 +229,16 @@ export function migrateStorage(
228
229
  *
229
230
  * @param hooks - Dependencies for creating initial block and plugin data
230
231
  * @returns Initial storage as branded JSON string
232
+ * @throws If initialDataFn or createPluginData throws
231
233
  */
232
234
  export function createInitialStorage(hooks: InitialStorageHooks): StringifiedJson<BlockStorage> {
233
235
  const blockDefault = hooks.getDefaultBlockData();
234
236
  const pluginRegistry = hooks.getPluginRegistry();
235
237
 
236
- const plugins: Record<string, VersionedData<unknown>> = {};
237
- for (const pluginId of Object.keys(pluginRegistry)) {
238
- const initial = hooks.createPluginData(pluginId);
239
- plugins[pluginId] = { __dataVersion: initial.version, __data: initial.data };
238
+ const plugins: Record<PluginHandle, VersionedData<unknown>> = {};
239
+ for (const handle of Object.keys(pluginRegistry) as PluginHandle[]) {
240
+ const initial = hooks.createPluginData(handle);
241
+ plugins[handle] = { __dataVersion: initial.version, __data: initial.data };
240
242
  }
241
243
 
242
244
  const storage: BlockStorage = {
@@ -1,55 +1,9 @@
1
- import type {
2
- AxisId,
3
- AxisSpecNormalized,
4
- CanonicalizedJson,
5
- PColumn,
6
- PColumnSpec,
7
- PFrameHandle,
8
- PObjectId,
9
- } from "@milaboratories/pl-model-common";
10
- import {
11
- Annotation,
12
- canonicalizeJson,
13
- getAxisId,
14
- getColumnIdAndSpec,
15
- LinkerMap,
16
- matchAxisId,
17
- readAnnotation,
18
- readAnnotationJson,
19
- stringifyJson,
20
- } from "@milaboratories/pl-model-common";
1
+ import type { PColumn, PColumnSpec, PFrameHandle } from "@milaboratories/pl-model-common";
2
+ import { Annotation, readAnnotationJson } from "@milaboratories/pl-model-common";
21
3
  import type { PColumnDataUniversal, RenderCtxBase } from "../render";
22
4
  import { getAllRelatedColumns, getRelatedColumns } from "../pframe_utils/columns";
23
-
24
- /** Create id for column copy with added keys in axes domains */
25
- const colId = (id: PObjectId, domains: (Record<string, string> | undefined)[]) => {
26
- let wid = id.toString();
27
- domains?.forEach((domain) => {
28
- if (domain) {
29
- for (const [k, v] of Object.entries(domain)) {
30
- wid += k;
31
- wid += v;
32
- }
33
- }
34
- });
35
- return wid;
36
- };
37
-
38
- /** All combinations with 1 key from each list */
39
- function getKeysCombinations(idsLists: AxisId[][]) {
40
- if (!idsLists.length) {
41
- return [];
42
- }
43
- let result: AxisId[][] = [[]];
44
- idsLists.forEach((list) => {
45
- const nextResult: AxisId[][] = [];
46
- list.forEach((key) => {
47
- nextResult.push(...result.map((resultItem) => [...resultItem, key]));
48
- });
49
- result = nextResult;
50
- });
51
- return result;
52
- }
5
+ export type { AxesVault } from "../pframe_utils/axes";
6
+ export { enrichCompatible, getAvailableWithLinkersAxes } from "../pframe_utils/axes";
53
7
 
54
8
  export function isHiddenFromGraphColumn(column: PColumnSpec): boolean {
55
9
  return !!readAnnotationJson(column, Annotation.HideDataFromGraphs);
@@ -59,123 +13,6 @@ export function isHiddenFromUIColumn(column: PColumnSpec): boolean {
59
13
  return !!readAnnotationJson(column, Annotation.HideDataFromUi);
60
14
  }
61
15
 
62
- export type AxesVault = Map<CanonicalizedJson<AxisId>, AxisSpecNormalized>;
63
-
64
- export function getAvailableWithLinkersAxes(
65
- linkerColumns: PColumn<PColumnDataUniversal>[],
66
- blockAxes: AxesVault,
67
- ): AxesVault {
68
- const linkerMap = LinkerMap.fromColumns(linkerColumns.map(getColumnIdAndSpec));
69
- const availableAxes = linkerMap.getReachableByLinkersAxesFromAxesNormalized(
70
- [...blockAxes.values()],
71
- (linkerKeyId, sourceAxisId) => matchAxisId(sourceAxisId, linkerKeyId),
72
- );
73
-
74
- return new Map(
75
- availableAxes.map((axisSpec) => {
76
- const id = getAxisId(axisSpec);
77
- return [canonicalizeJson(id), axisSpec];
78
- }),
79
- );
80
- }
81
- /** Add columns with fully compatible axes created from partial compatible ones */
82
- export function enrichCompatible<T extends Omit<PColumn<PColumnDataUniversal>, "data">>(
83
- blockAxes: AxesVault,
84
- columns: T[],
85
- ): T[] {
86
- return columns.flatMap((column) => getAdditionalColumnsForColumn(blockAxes, column));
87
- }
88
-
89
- function getAdditionalColumnsForColumn<T extends Omit<PColumn<PColumnDataUniversal>, "data">>(
90
- blockAxes: AxesVault,
91
- column: T,
92
- ): T[] {
93
- const columnAxesIds = column.spec.axesSpec.map(getAxisId);
94
-
95
- if (columnAxesIds.every((id) => blockAxes.has(canonicalizeJson(id)))) {
96
- return [column]; // the column is compatible with its own domains without modifications
97
- }
98
-
99
- // options with different possible domains for every axis of secondary column
100
- const secondaryIdsOptions = columnAxesIds.map((id) => {
101
- const result = [];
102
- for (const [_, mainId] of blockAxes) {
103
- if (matchAxisId(mainId, id) && !matchAxisId(id, mainId)) {
104
- result.push(mainId);
105
- }
106
- }
107
- return result;
108
- });
109
- // all possible combinations of axes with added domains
110
- const secondaryIdsVariants = getKeysCombinations(secondaryIdsOptions);
111
-
112
- // sets of added to column domain fields
113
- const allAddedDomainValues = new Set<string>();
114
- const addedNotToAllVariantsDomainValues = new Set<string>();
115
- const addedByVariantsDomainValues = secondaryIdsVariants.map((idsList) => {
116
- const addedSet = new Set<string>();
117
- idsList.map((axisId, idx) => {
118
- const d1 = column.spec.axesSpec[idx].domain;
119
- const d2 = axisId.domain;
120
- Object.entries(d2 ?? {}).forEach(([key, value]) => {
121
- if (d1?.[key] === undefined) {
122
- const item = JSON.stringify([key, value]);
123
- addedSet.add(item);
124
- allAddedDomainValues.add(item);
125
- }
126
- });
127
- return {
128
- ...axisId,
129
- annotations: column.spec.axesSpec[idx].annotations,
130
- };
131
- });
132
- return addedSet;
133
- });
134
- [...allAddedDomainValues].forEach((addedPart) => {
135
- if (addedByVariantsDomainValues.some((s) => !s.has(addedPart))) {
136
- addedNotToAllVariantsDomainValues.add(addedPart);
137
- }
138
- });
139
-
140
- const additionalColumns = secondaryIdsVariants.map((idsList, idx) => {
141
- const id = colId(
142
- column.id,
143
- idsList.map((id) => id.domain),
144
- );
145
-
146
- const label = readAnnotation(column.spec, Annotation.Label) ?? "";
147
- const labelDomainPart = [...addedByVariantsDomainValues[idx]]
148
- .filter((str) => addedNotToAllVariantsDomainValues.has(str))
149
- .sort()
150
- .map((v) => JSON.parse(v)?.[1]) // use in labels only domain values, but sort them by key to save the same order in all column variants
151
- .join(" / ");
152
-
153
- const annotations: Annotation = {
154
- ...column.spec.annotations,
155
- [Annotation.Graph.IsVirtual]: stringifyJson(true),
156
- };
157
- if (label || labelDomainPart) {
158
- annotations[Annotation.Label] =
159
- label && labelDomainPart ? label + " / " + labelDomainPart : label + labelDomainPart;
160
- }
161
-
162
- return {
163
- ...column,
164
- id: id as PObjectId,
165
- spec: {
166
- ...column.spec,
167
- axesSpec: idsList.map((axisId, idx) => ({
168
- ...axisId,
169
- annotations: column.spec.axesSpec[idx].annotations,
170
- })),
171
- annotations,
172
- },
173
- };
174
- });
175
-
176
- return [column, ...additionalColumns];
177
- }
178
-
179
16
  /**
180
17
  The aim of createPFrameForGraphs: to create pframe with block’s columns and all compatible columns from result pool
181
18
  (including linker columns and all label columns).
package/src/index.ts CHANGED
@@ -1,6 +1,27 @@
1
1
  export * from "./block_state_patch";
2
2
  export * from "./block_state_util";
3
- export * from "./block_storage";
3
+ export * from "./plugin_handle";
4
+ export {
5
+ type BlockStorageSchemaVersion,
6
+ type PluginName,
7
+ type PluginRegistry,
8
+ type VersionedData,
9
+ type BlockStorage,
10
+ isBlockStorage,
11
+ createBlockStorage,
12
+ normalizeBlockStorage,
13
+ getStorageData,
14
+ deriveDataFromStorage,
15
+ type MutateStoragePayload,
16
+ updateStorageData,
17
+ type StorageDebugView,
18
+ type MigrationSuccess,
19
+ type MigrationFailure,
20
+ type MigrationResult,
21
+ type MigrateBlockStorageConfig,
22
+ migrateBlockStorage,
23
+ getPluginData,
24
+ } from "./block_storage";
4
25
  export * from "./block_storage_facade";
5
26
  export * from "./block_model_legacy";
6
27
  export { BlockModelV3 } from "./block_model";
@@ -8,13 +29,14 @@ export type { PluginInstance, ParamsInput } from "./block_model";
8
29
  export {
9
30
  DataModel,
10
31
  DataModelBuilder,
32
+ DataMigrationError,
11
33
  DataUnrecoverableError,
12
34
  isDataUnrecoverableError,
13
35
  defaultRecover,
14
36
  makeDataVersioned,
15
37
  } from "./block_migrations";
16
38
  export type { LegacyV1State } from "./block_migrations";
17
- export { PluginModel } from "./plugin_model";
39
+ export * from "./plugin_model";
18
40
  export * from "./bconfig";
19
41
  export * from "./components";
20
42
  export * from "./config";