@platforma-sdk/model 1.8.19 → 1.9.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.
Files changed (53) hide show
  1. package/dist/bconfig/container.d.ts +46 -0
  2. package/dist/bconfig/container.d.ts.map +1 -0
  3. package/dist/bconfig/index.d.ts +7 -0
  4. package/dist/bconfig/index.d.ts.map +1 -0
  5. package/dist/bconfig/lambdas.d.ts +33 -0
  6. package/dist/bconfig/lambdas.d.ts.map +1 -0
  7. package/dist/bconfig/normalization.d.ts +13 -0
  8. package/dist/bconfig/normalization.d.ts.map +1 -0
  9. package/dist/bconfig/types.d.ts +11 -0
  10. package/dist/bconfig/types.d.ts.map +1 -0
  11. package/dist/bconfig/utils.d.ts +7 -0
  12. package/dist/bconfig/utils.d.ts.map +1 -0
  13. package/dist/bconfig/v3.d.ts +30 -0
  14. package/dist/bconfig/v3.d.ts.map +1 -0
  15. package/dist/builder.d.ts +45 -65
  16. package/dist/builder.d.ts.map +1 -1
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +428 -251
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/internal.d.ts +3 -2
  24. package/dist/internal.d.ts.map +1 -1
  25. package/dist/platforma.d.ts +3 -2
  26. package/dist/platforma.d.ts.map +1 -1
  27. package/dist/raw_globals.d.ts.map +1 -1
  28. package/dist/render/accessor.d.ts +23 -0
  29. package/dist/render/accessor.d.ts.map +1 -1
  30. package/dist/render/api.d.ts +2 -0
  31. package/dist/render/api.d.ts.map +1 -1
  32. package/dist/render/internal.d.ts +4 -0
  33. package/dist/render/internal.d.ts.map +1 -1
  34. package/dist/version.d.ts +1 -1
  35. package/dist/version.d.ts.map +1 -1
  36. package/package.json +3 -3
  37. package/src/bconfig/container.ts +58 -0
  38. package/src/bconfig/index.ts +6 -0
  39. package/src/bconfig/lambdas.ts +44 -0
  40. package/src/bconfig/normalization.ts +120 -0
  41. package/src/bconfig/types.ts +18 -0
  42. package/src/bconfig/utils.ts +8 -0
  43. package/src/bconfig/v3.ts +46 -0
  44. package/src/builder.ts +165 -141
  45. package/src/global.d.ts +1 -1
  46. package/src/index.ts +1 -0
  47. package/src/internal.ts +1 -2
  48. package/src/platforma.ts +1 -2
  49. package/src/raw_globals.ts +2 -1
  50. package/src/render/accessor.ts +73 -0
  51. package/src/render/api.ts +22 -10
  52. package/src/render/internal.ts +12 -0
  53. package/src/typing.test.ts +5 -4
package/src/builder.ts CHANGED
@@ -4,22 +4,17 @@ import { getPlatformaInstance, isInUI, tryRegisterCallback } from './internal';
4
4
  import { Platforma } from './platforma';
5
5
  import { InferRenderFunctionReturn, RenderCtx, RenderFunction } from './render';
6
6
  import { PlatformaSDKVersion } from './version';
7
-
8
- type StdCtxArgsOnly<Args, UiState = undefined> = {
9
- readonly $blockId: string;
10
- readonly $args: Args;
11
- readonly $ui: UiState;
12
- };
13
-
14
- export type StdCtx<Args, UiState = undefined> = StdCtxArgsOnly<Args, UiState> & {
15
- readonly $prod: PlResourceEntry;
16
- readonly $staging: PlResourceEntry;
17
- };
18
-
19
- export type ResolveCfgType<Cfg extends TypedConfig, Args, UiState = undefined> = ConfigResult<
20
- Cfg,
21
- StdCtx<Args, UiState>
22
- >;
7
+ import {
8
+ TypedConfigOrConfigLambda,
9
+ ConfigRenderLambda,
10
+ StdCtxArgsOnly,
11
+ DeriveHref,
12
+ ResolveCfgType,
13
+ ExtractFunctionHandleReturn,
14
+ BlockConfigContainer,
15
+ downgradeCfgOrLambda,
16
+ ConfigRenderLambdaFlags
17
+ } from './bconfig';
23
18
 
24
19
  type SectionsExpectedType = readonly BlockSection[];
25
20
 
@@ -45,131 +40,57 @@ type InputsValidRFChecked<RF extends Function> = Checked<
45
40
  InferRenderFunctionReturn<RF> extends InputsValidExpectedType ? true : false
46
41
  >;
47
42
 
48
- export type Code = {
49
- type: 'plain';
50
- content: string;
51
- };
52
-
53
- /** Field key to attach ConfAction information to a config type. */
54
- declare const __function_handle__: unique symbol;
55
-
56
- /** Creates branded Cfg type */
57
- export type FunctionHandle<Return = unknown> = string & { [__function_handle__]: Return };
58
-
59
- export type ExtractFunctionHandleReturn<Func extends FunctionHandle> =
60
- Func[typeof __function_handle__];
61
-
62
- export type TypedConfigOrFunctionHandle = TypedConfig | FunctionHandle;
63
-
64
- export function isFunctionHandle(cfgOrFh: TypedConfigOrFunctionHandle): cfgOrFh is FunctionHandle {
65
- return typeof cfgOrFh === 'string';
66
- }
67
-
68
- type OnlyString<S> = S extends string ? S : '';
69
-
70
- // prettier-ignore
71
- export type DeriveHref<S> = S extends readonly BlockSection[]
72
- ? OnlyString<Extract<S[number], { type: 'link' }>['href']>
73
- : never;
74
-
75
- /** This structure is rendered from the configuration, type can accommodate any
76
- * version of config structure. */
77
- export type BlockConfigUniversal<
78
- Args = unknown,
79
- Outputs extends Record<string, TypedConfigOrFunctionHandle> = Record<
80
- string,
81
- TypedConfigOrFunctionHandle
82
- >
83
- > = {
84
- /** SDK version used by the block */
85
- readonly sdkVersion: string;
86
-
87
- /** Main rendering mode for the block */
88
- readonly renderingMode: BlockRenderingMode;
89
-
90
- /** Initial value for the args when block is added to the project */
91
- readonly initialArgs: Args;
92
-
93
- /** @deprecated */
94
- readonly canRun?: TypedConfigOrFunctionHandle;
95
-
96
- /**
97
- * Config to determine whether the block can be executed with current
98
- * arguments.
99
- *
100
- * Optional to support earlier SDK version configs.
101
- * */
102
- readonly inputsValid?: TypedConfigOrFunctionHandle;
103
-
104
- /** Configuration to derive list of section for the left overview panel */
105
- readonly sections: TypedConfigOrFunctionHandle;
106
-
107
- /** Configuration for the output cells */
108
- readonly outputs: Outputs;
109
-
110
- /** Config code bundle */
111
- readonly code?: Code;
112
- };
113
-
114
- /** This structure is rendered from the configuration */
115
- export type BlockConfig<
116
- Args = unknown,
117
- Outputs extends Record<string, TypedConfigOrFunctionHandle> = Record<
118
- string,
119
- TypedConfigOrFunctionHandle
120
- >
121
- > = Required<Omit<BlockConfigUniversal<Args, Outputs>, 'canRun' | 'code'>> &
122
- Pick<BlockConfigUniversal<Args, Outputs>, 'code'>;
123
-
124
- /** Takes universal config, and converts it into latest structure */
125
- export function normalizeBlockConfig<
126
- Args,
127
- Outputs extends Record<string, TypedConfigOrFunctionHandle>
128
- >(cfg: BlockConfigUniversal<Args, Outputs>): BlockConfig<Args, Outputs> {
129
- if (cfg.inputsValid !== undefined) return cfg as BlockConfig<Args, Outputs>;
130
- else {
131
- if (cfg.canRun === undefined)
132
- throw new Error(`Malformed config, SDK version ${cfg.sdkVersion}`);
133
- const latest = { ...cfg, inputsValid: cfg.canRun };
134
- delete latest['canRun'];
135
- return latest;
136
- }
137
- }
43
+ type NoOb = Record<string, never>;
138
44
 
139
45
  /** Main entry point that each block should use in it's "config" module. Don't forget
140
46
  * to call {@link done()} at the end of configuration. Value returned by this builder must be
141
47
  * exported as constant with name "platforma" from the "config" module. */
142
48
  export class BlockModel<
143
49
  Args,
144
- OutputsCfg extends Record<string, TypedConfigOrFunctionHandle>,
50
+ OutputsCfg extends Record<string, TypedConfigOrConfigLambda>,
145
51
  UiState,
146
52
  Href extends `/${string}` = '/'
147
53
  > {
148
54
  private constructor(
149
55
  private readonly _renderingMode: BlockRenderingMode,
150
56
  private readonly _initialArgs: Args | undefined,
57
+ private readonly _initialUiState: UiState,
151
58
  private readonly _outputs: OutputsCfg,
152
- private readonly _inputsValid: TypedConfigOrFunctionHandle,
153
- private readonly _sections: TypedConfigOrFunctionHandle
154
- ) { }
59
+ private readonly _inputsValid: TypedConfigOrConfigLambda,
60
+ private readonly _sections: TypedConfigOrConfigLambda,
61
+ private readonly _title: ConfigRenderLambda | undefined
62
+ ) {}
155
63
 
156
64
  /** Initiates configuration builder */
157
- public static create<Args, UiState = undefined>(
158
- renderingMode: BlockRenderingMode = 'Heavy'
159
- ): BlockModel<Args, {}, UiState> {
160
- return new BlockModel<Args, {}, UiState>(
65
+ public static create(renderingMode: BlockRenderingMode): BlockModel<NoOb, {}, NoOb>;
66
+ /** Initiates configuration builder */
67
+ public static create(): BlockModel<NoOb, {}, NoOb>;
68
+ /**
69
+ * Initiates configuration builder
70
+ * @deprecated use create method without generic parameter
71
+ */
72
+ public static create<Args>(renderingMode: BlockRenderingMode): BlockModel<Args, {}, NoOb>;
73
+ /**
74
+ * Initiates configuration builder
75
+ * @deprecated use create method without generic parameter
76
+ */
77
+ public static create<Args>(): BlockModel<Args, {}, NoOb>;
78
+ public static create(renderingMode: BlockRenderingMode = 'Heavy'): BlockModel<NoOb, {}, NoOb> {
79
+ return new BlockModel<NoOb, {}, NoOb>(
161
80
  renderingMode,
162
81
  undefined,
163
82
  {},
83
+ {},
164
84
  getImmediate(true),
165
- getImmediate([])
85
+ getImmediate([]),
86
+ undefined
166
87
  );
167
88
  }
168
89
 
169
90
  /**
170
91
  * Add output cell to the configuration
171
92
  *
172
- * @param key cell name, that can be used to retrieve the rendered value
93
+ * @param key output cell name, that can be later used to retrieve the rendered value
173
94
  * @param cfg configuration describing how to render cell value from the blocks
174
95
  * workflow outputs
175
96
  * */
@@ -177,45 +98,76 @@ export class BlockModel<
177
98
  key: Key,
178
99
  cfg: Cfg
179
100
  ): BlockModel<Args, OutputsCfg & { [K in Key]: Cfg }, UiState, Href>;
101
+ /**
102
+ * Add output cell to the configuration
103
+ *
104
+ * @param key output cell name, that can be later used to retrieve the rendered value
105
+ * @param rf callback calculating output value using context, that allows to access
106
+ * workflows outputs and interact with platforma drivers
107
+ * @param flags additional flags that may alter lambda rendering procedure
108
+ * */
180
109
  public output<const Key extends string, const RF extends RenderFunction<Args, UiState>>(
181
110
  key: Key,
182
- rf: RF
111
+ rf: RF,
112
+ flags?: ConfigRenderLambdaFlags
183
113
  ): BlockModel<
184
114
  Args,
185
- OutputsCfg & { [K in Key]: FunctionHandle<InferRenderFunctionReturn<RF>> },
115
+ OutputsCfg & { [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>> },
186
116
  UiState,
187
117
  Href
188
118
  >;
189
119
  public output(
190
120
  key: string,
191
- cfgOrRf: TypedConfig | Function
121
+ cfgOrRf: TypedConfig | Function,
122
+ flags: ConfigRenderLambdaFlags = {}
192
123
  ): BlockModel<Args, OutputsCfg, UiState, Href> {
193
124
  if (typeof cfgOrRf === 'function') {
194
- const functionHandle = `output#${key}` as FunctionHandle;
195
- tryRegisterCallback(functionHandle, () => cfgOrRf(new RenderCtx()));
125
+ const handle = `output#${key}`;
126
+ tryRegisterCallback(handle, () => cfgOrRf(new RenderCtx()));
196
127
  return new BlockModel(
197
128
  this._renderingMode,
198
129
  this._initialArgs,
130
+ this._initialUiState,
199
131
  {
200
132
  ...this._outputs,
201
- [key]: functionHandle
133
+ [key]: {
134
+ __renderLambda: true,
135
+ handle,
136
+ ...flags
137
+ } satisfies ConfigRenderLambda
202
138
  },
203
139
  this._inputsValid,
204
- this._sections
140
+ this._sections,
141
+ this._title
205
142
  );
206
143
  } else
207
144
  return new BlockModel(
208
145
  this._renderingMode,
209
146
  this._initialArgs,
147
+ this._initialUiState,
210
148
  {
211
149
  ...this._outputs,
212
150
  [key]: cfgOrRf
213
151
  },
214
152
  this._inputsValid,
215
- this._sections
153
+ this._sections,
154
+ this._title
216
155
  );
217
156
  }
218
157
 
158
+ /** Shortcut for {@link output} with retentive flag set to true. */
159
+ public retentiveOutput<const Key extends string, const RF extends RenderFunction<Args, UiState>>(
160
+ key: Key,
161
+ rf: RF
162
+ ): BlockModel<
163
+ Args,
164
+ OutputsCfg & { [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>> },
165
+ UiState,
166
+ Href
167
+ > {
168
+ return this.output(key, rf, { retentive: true });
169
+ }
170
+
219
171
  /** @deprecated */
220
172
  public canRun<Cfg extends TypedConfig>(
221
173
  cfg: Cfg & InputsValidCfgChecked<Cfg, Args, UiState>
@@ -239,17 +191,24 @@ export class BlockModel<
239
191
  return new BlockModel<Args, OutputsCfg, UiState>(
240
192
  this._renderingMode,
241
193
  this._initialArgs,
194
+ this._initialUiState,
242
195
  this._outputs,
243
- 'inputsValid' as FunctionHandle,
244
- this._sections
196
+ {
197
+ __renderLambda: true,
198
+ handle: 'inputsValid'
199
+ } satisfies ConfigRenderLambda,
200
+ this._sections,
201
+ this._title
245
202
  );
246
203
  } else
247
204
  return new BlockModel<Args, OutputsCfg, UiState>(
248
205
  this._renderingMode,
249
206
  this._initialArgs,
207
+ this._initialUiState,
250
208
  this._outputs,
251
209
  cfgOrRf,
252
- this._sections
210
+ this._sections,
211
+ this._title
253
212
  );
254
213
  }
255
214
 
@@ -268,7 +227,9 @@ export class BlockModel<
268
227
  }
269
228
 
270
229
  /** Sets the config to generate list of section in the left block overviews panel */
271
- public sections<const S extends SectionsExpectedType,>(rf: S): BlockModel<Args, OutputsCfg, UiState, DeriveHref<S>>;
230
+ public sections<const S extends SectionsExpectedType>(
231
+ rf: S
232
+ ): BlockModel<Args, OutputsCfg, UiState, DeriveHref<S>>;
272
233
  public sections<
273
234
  const Ret extends SectionsExpectedType,
274
235
  const RF extends RenderFunction<Args, UiState, Ret>
@@ -284,36 +245,85 @@ export class BlockModel<
284
245
  public sections(
285
246
  arrOrCfgOrRf: SectionsExpectedType | TypedConfig | Function
286
247
  ): BlockModel<Args, OutputsCfg, UiState, `/${string}`> {
287
- if (Array.isArray(arrOrCfgOrRf)){
288
- return this.sections(getImmediate(arrOrCfgOrRf))
248
+ if (Array.isArray(arrOrCfgOrRf)) {
249
+ return this.sections(getImmediate(arrOrCfgOrRf));
289
250
  } else if (typeof arrOrCfgOrRf === 'function') {
290
251
  tryRegisterCallback('sections', () => arrOrCfgOrRf(new RenderCtx()));
291
252
  return new BlockModel<Args, OutputsCfg, UiState>(
292
253
  this._renderingMode,
293
254
  this._initialArgs,
255
+ this._initialUiState,
294
256
  this._outputs,
295
257
  this._inputsValid,
296
- 'sections' as FunctionHandle
258
+ { __renderLambda: true, handle: 'sections' } as ConfigRenderLambda,
259
+ this._title
297
260
  );
298
261
  } else
299
262
  return new BlockModel<Args, OutputsCfg, UiState>(
300
263
  this._renderingMode,
301
264
  this._initialArgs,
265
+ this._initialUiState,
302
266
  this._outputs,
303
267
  this._inputsValid,
304
- arrOrCfgOrRf as TypedConfig
268
+ arrOrCfgOrRf as TypedConfig,
269
+ this._title
305
270
  );
306
271
  }
307
272
 
273
+ public title(
274
+ rf: RenderFunction<Args, UiState, string>
275
+ ): BlockModel<Args, OutputsCfg, UiState, Href> {
276
+ tryRegisterCallback('title', () => rf(new RenderCtx()));
277
+ return new BlockModel<Args, OutputsCfg, UiState, Href>(
278
+ this._renderingMode,
279
+ this._initialArgs,
280
+ this._initialUiState,
281
+ this._outputs,
282
+ this._inputsValid,
283
+ this._sections,
284
+ { __renderLambda: true, handle: 'title' } as ConfigRenderLambda
285
+ );
286
+ }
308
287
 
309
- /** Sets initial args for the block, this value must be specified. */
288
+ /**
289
+ * Sets initial args for the block, this value must be specified.
290
+ * @deprecated use {@link withArgs}
291
+ * */
310
292
  public initialArgs(value: Args): BlockModel<Args, OutputsCfg, UiState, Href> {
311
293
  return new BlockModel<Args, OutputsCfg, UiState, Href>(
312
294
  this._renderingMode,
313
295
  value,
296
+ this._initialUiState,
297
+ this._outputs,
298
+ this._inputsValid,
299
+ this._sections,
300
+ this._title
301
+ );
302
+ }
303
+
304
+ /** Sets initial args for the block, this value must be specified. */
305
+ public withArgs<Args>(initialValue: Args): BlockModel<Args, OutputsCfg, UiState, Href> {
306
+ return new BlockModel<Args, OutputsCfg, UiState, Href>(
307
+ this._renderingMode,
308
+ initialValue,
309
+ this._initialUiState,
310
+ this._outputs,
311
+ this._inputsValid,
312
+ this._sections,
313
+ this._title
314
+ );
315
+ }
316
+
317
+ /** Defines type and sets initial value for block UiState. */
318
+ public withUiState<UiState>(initialValue: UiState): BlockModel<Args, OutputsCfg, UiState, Href> {
319
+ return new BlockModel<Args, OutputsCfg, UiState, Href>(
320
+ this._renderingMode,
321
+ this._initialArgs,
322
+ initialValue,
314
323
  this._outputs,
315
324
  this._inputsValid,
316
- this._sections
325
+ this._sections,
326
+ this._title
317
327
  );
318
328
  }
319
329
 
@@ -328,32 +338,46 @@ export class BlockModel<
328
338
  > {
329
339
  if (this._initialArgs === undefined) throw new Error('Initial arguments not set.');
330
340
 
331
- const config: BlockConfig<Args, OutputsCfg> = {
341
+ const config: BlockConfigContainer = {
342
+ v3: {
343
+ sdkVersion: PlatformaSDKVersion,
344
+ renderingMode: this._renderingMode,
345
+ initialArgs: this._initialArgs,
346
+ initialUiState: this._initialUiState,
347
+ inputsValid: this._inputsValid,
348
+ sections: this._sections,
349
+ title: this._title,
350
+ outputs: this._outputs
351
+ },
352
+
353
+ // fields below are added to allow previous desktop versions read generated configs
332
354
  sdkVersion: PlatformaSDKVersion,
333
355
  renderingMode: this._renderingMode,
334
356
  initialArgs: this._initialArgs,
335
- inputsValid: this._inputsValid,
336
- sections: this._sections,
337
- outputs: this._outputs
357
+ inputsValid: downgradeCfgOrLambda(this._inputsValid),
358
+ sections: downgradeCfgOrLambda(this._sections),
359
+ outputs: Object.fromEntries(
360
+ Object.entries(this._outputs).map(([key, value]) => [key, downgradeCfgOrLambda(value)])
361
+ )
338
362
  };
339
363
 
340
364
  if (!isInUI())
341
365
  // we are in the configuration rendering routine, not in actual UI
342
366
  return { config } as any;
343
367
  // normal operation inside the UI
344
- else return getPlatformaInstance(config) as any;
368
+ else return getPlatformaInstance({ sdkVersion: PlatformaSDKVersion }) as any;
345
369
  }
346
370
  }
347
371
 
348
372
  export type InferOutputType<CfgOrFH, Args, UiState> = CfgOrFH extends TypedConfig
349
373
  ? ResolveCfgType<CfgOrFH, Args, UiState>
350
- : CfgOrFH extends FunctionHandle
374
+ : CfgOrFH extends ConfigRenderLambda
351
375
  ? ExtractFunctionHandleReturn<CfgOrFH>
352
376
  : never;
353
377
 
354
378
  type InferOutputsFromConfigs<
355
379
  Args,
356
- OutputsCfg extends Record<string, TypedConfigOrFunctionHandle>,
380
+ OutputsCfg extends Record<string, TypedConfigOrConfigLambda>,
357
381
  UiState
358
382
  > = {
359
383
  [Key in keyof OutputsCfg]: ValueOrErrors<InferOutputType<OutputsCfg[Key], Args, UiState>>;
package/src/global.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  declare global {
2
2
  /** Global factory method returning platforma instance */
3
- var getPlatforma: PlatformaFactory;
3
+ var getPlatforma: PlatformaSDKVersion;
4
4
  var platforma: Platforma;
5
5
 
6
6
  function getEnvironmentValue(name: string): string | undefined;
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './block_state_patch';
2
2
  export * from './block_state_util';
3
3
  export * from './builder';
4
+ export * from './bconfig';
4
5
  export * from './components';
5
6
  export * from './config';
6
7
  export * from './pframe';
package/src/internal.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import {} from './global';
2
2
  import { Platforma, PlatformaFactory } from './platforma';
3
- import { BlockConfig } from './builder';
4
3
  import { FutureHandle, GlobalCfgRenderCtx } from './render/internal';
5
4
 
6
5
  /** Utility code helping to identify whether the code is running in actual UI environment */
@@ -11,7 +10,7 @@ export function isInUI() {
11
10
  }
12
11
 
13
12
  /** Utility code helping to retrieve a platforma instance form the environment */
14
- export function getPlatformaInstance(config?: BlockConfig): Platforma {
13
+ export function getPlatformaInstance(config?: {sdkVersion: string}): Platforma {
15
14
  if (config && typeof globalThis.getPlatforma === 'function')
16
15
  return globalThis.getPlatforma(config);
17
16
  else if (typeof globalThis.platforma !== 'undefined') return globalThis.platforma;
package/src/platforma.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { BlockApi } from './block_api';
2
2
  import { BlockOutputsBase, BlockState, DriverKit, ValueOrErrors } from '@milaboratories/pl-model-common';
3
- import { BlockConfig } from './builder';
4
3
  import { SdkInfo } from './sdk_info';
5
4
  import { BlockStatePatch } from './block_state_patch';
6
5
 
@@ -29,7 +28,7 @@ export type InferUiState<Pl extends Platforma> =
29
28
  export type InferHrefType<Pl extends Platforma> =
30
29
  Pl extends Platforma<unknown, BlockOutputsBase, unknown, infer Href> ? Href : never;
31
30
 
32
- export type PlatformaFactory = (config: BlockConfig) => Platforma;
31
+ export type PlatformaFactory = (config: {sdkVersion: string}) => Platforma;
33
32
 
34
33
  export type InferBlockState<Pl extends Platforma> = BlockState<
35
34
  InferArgsType<Pl>,
@@ -1,7 +1,8 @@
1
1
  import {} from './global';
2
2
  import { getPlatformaInstance } from './internal';
3
3
  import { Platforma } from './platforma';
4
+ import { PlatformaSDKVersion } from './version';
4
5
 
5
6
  export function getRawPlatformaInstance(): Platforma {
6
- return getPlatformaInstance();
7
+ return getPlatformaInstance({ sdkVersion: PlatformaSDKVersion });
7
8
  }
@@ -25,6 +25,24 @@ function wrapAccessor(handle: AccessorHandle | undefined): TreeNodeAccessor | un
25
25
  return handle === undefined ? undefined : new TreeNodeAccessor(handle);
26
26
  }
27
27
 
28
+ type FieldMapOps = {
29
+ /**
30
+ * Type of fields to interate over.
31
+ * (default 'Input')
32
+ * */
33
+ readonly fieldType?: 'Input' | 'Output' | 'Dynamic';
34
+ /**
35
+ * If not locked, `undefined` value will be returned. Do nothing if mapping `Dynamic` fields.
36
+ * (default true)
37
+ * */
38
+ readonly requireLocked?: boolean;
39
+ /**
40
+ * Will skip unresolved fields.
41
+ * (default false)
42
+ * */
43
+ readonly skipUnresolved?: boolean;
44
+ };
45
+
28
46
  /** Represent resource tree node accessor */
29
47
  export class TreeNodeAccessor {
30
48
  constructor(public readonly handle: AccessorHandle) {}
@@ -220,4 +238,59 @@ export class TreeNodeAccessor {
220
238
  public getLogHandle(): FutureRef<AnyLogHandle | undefined> {
221
239
  return new FutureRef(getCfgRenderCtx().getLogHandle(this.handle));
222
240
  }
241
+
242
+ public allFieldsResolved(fieldType: 'Input' | 'Output' = 'Input'): boolean {
243
+ switch (fieldType) {
244
+ case 'Input':
245
+ return (
246
+ this.getInputsLocked() &&
247
+ this.listInputFields().every(
248
+ (field) => this.resolve({ field, assertFieldType: 'Input' }) !== undefined
249
+ )
250
+ );
251
+ case 'Output':
252
+ return (
253
+ this.getOutputsLocked() &&
254
+ this.listOutputFields().every(
255
+ (field) => this.resolve({ field, assertFieldType: 'Output' }) !== undefined
256
+ )
257
+ );
258
+ }
259
+ }
260
+
261
+ public mapFields<T>(
262
+ _mapping: (name: string, value: TreeNodeAccessor) => T,
263
+ _ops: FieldMapOps & { skipUnresolved: true }
264
+ ): T[] | undefined;
265
+ public mapFields<T>(
266
+ _mapping: (name: string, value: TreeNodeAccessor | undefined) => T,
267
+ _ops?: FieldMapOps
268
+ ): T[] | undefined;
269
+ public mapFields<T>(
270
+ _mapping: (name: string, value: TreeNodeAccessor) => T,
271
+ _ops?: FieldMapOps
272
+ ): T[] | undefined {
273
+ const { fieldType, requireLocked, skipUnresolved } = {
274
+ fieldType: 'Input' as const,
275
+ requireLocked: true,
276
+ skipUnresolved: false,
277
+ ..._ops
278
+ };
279
+ const mapping = _mapping as (name: string, value: TreeNodeAccessor | undefined) => T;
280
+ if (requireLocked) {
281
+ if (fieldType === 'Input' && !this.getInputsLocked()) return undefined;
282
+ if (fieldType === 'Output' && !this.getOutputsLocked()) return undefined;
283
+ }
284
+ const fieldList =
285
+ fieldType === 'Input'
286
+ ? this.listInputFields()
287
+ : fieldType === 'Output'
288
+ ? this.listOutputFields()
289
+ : this.listDynamicFields();
290
+ let fieldEntries = fieldList.map(
291
+ (field) => [field, this.resolve({ field, assertFieldType: fieldType })] as const
292
+ );
293
+ if (skipUnresolved) fieldEntries = fieldEntries.filter((e) => e[1] !== undefined);
294
+ return fieldEntries.map(([name, value]) => mapping(name, value));
295
+ }
223
296
  }
package/src/render/api.ts CHANGED
@@ -112,11 +112,15 @@ export class ResultPool {
112
112
  * @returns data associated with the ref
113
113
  */
114
114
  public getDataByRef(ref: Ref): PObject<TreeNodeAccessor> | undefined {
115
- // https://github.com/milaboratory/platforma/issues/100
116
- // @TODO use native pool method when available
117
- return this.getData().entries.find(
118
- (f) => f.ref.blockId === ref.blockId && f.ref.name === ref.name
119
- )?.obj;
115
+ // @TODO remove after 1 Jan 2025; forward compatibility
116
+ if (typeof this.ctx.getDataFromResultPoolByRef === 'undefined')
117
+ return this.getData().entries.find(
118
+ (f) => f.ref.blockId === ref.blockId && f.ref.name === ref.name
119
+ )?.obj;
120
+ return mapPObjectData(
121
+ this.ctx.getDataFromResultPoolByRef(ref.blockId, ref.name),
122
+ (handle) => new TreeNodeAccessor(handle)
123
+ );
120
124
  }
121
125
 
122
126
  /**
@@ -124,11 +128,12 @@ export class ResultPool {
124
128
  * @returns object spec associated with the ref
125
129
  */
126
130
  public getSpecByRef(ref: Ref): PObjectSpec | undefined {
127
- // https://github.com/milaboratory/platforma/issues/100
128
- // @TODO use native pool method when available
129
- return this.getSpecs().entries.find(
130
- (f) => f.ref.blockId === ref.blockId && f.ref.name === ref.name
131
- )?.obj;
131
+ // @TODO remove after 1 Jan 2025; forward compatibility
132
+ if (typeof this.ctx.getSpecFromResultPoolByRef === 'undefined')
133
+ return this.getSpecs().entries.find(
134
+ (f) => f.ref.blockId === ref.blockId && f.ref.name === ref.name
135
+ )?.obj;
136
+ return this.ctx.getSpecFromResultPoolByRef(ref.blockId, ref.name);
132
137
  }
133
138
 
134
139
  /**
@@ -275,9 +280,16 @@ export class RenderCtx<Args, UiState> {
275
280
  return this.ctx.createPTable(mapPTableDef(rawDef, (po) => mapPObjectData(po, (d) => d.handle)));
276
281
  }
277
282
 
283
+ /** @deprecated scheduled for removal from SDK */
278
284
  public getBlockLabel(blockId: string): string {
279
285
  return this.ctx.getBlockLabel(blockId);
280
286
  }
287
+
288
+ public getCurrentUnstableMarker(): string | undefined {
289
+ // @TODO remove after 1 Jan 2025; forward compatibility
290
+ if (typeof this.ctx.getCurrentUnstableMarker === 'undefined') return undefined;
291
+ return this.ctx.getCurrentUnstableMarker();
292
+ }
281
293
  }
282
294
 
283
295
  export type RenderFunction<Args = unknown, UiState = unknown, Ret = unknown> = (