@platforma-sdk/model 1.51.6 → 1.52.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 (89) hide show
  1. package/dist/bconfig/lambdas.d.ts +26 -4
  2. package/dist/bconfig/lambdas.d.ts.map +1 -1
  3. package/dist/bconfig/v3.d.ts +4 -2
  4. package/dist/bconfig/v3.d.ts.map +1 -1
  5. package/dist/block_api_v3.d.ts +32 -0
  6. package/dist/block_api_v3.d.ts.map +1 -0
  7. package/dist/block_migrations.cjs +138 -0
  8. package/dist/block_migrations.cjs.map +1 -0
  9. package/dist/block_migrations.d.ts +79 -0
  10. package/dist/block_migrations.d.ts.map +1 -0
  11. package/dist/block_migrations.js +136 -0
  12. package/dist/block_migrations.js.map +1 -0
  13. package/dist/block_model.cjs +222 -0
  14. package/dist/block_model.cjs.map +1 -0
  15. package/dist/block_model.d.ts +132 -0
  16. package/dist/block_model.d.ts.map +1 -0
  17. package/dist/block_model.js +220 -0
  18. package/dist/block_model.js.map +1 -0
  19. package/dist/block_storage.cjs +244 -0
  20. package/dist/block_storage.cjs.map +1 -0
  21. package/dist/block_storage.d.ts +208 -0
  22. package/dist/block_storage.d.ts.map +1 -0
  23. package/dist/block_storage.js +225 -0
  24. package/dist/block_storage.js.map +1 -0
  25. package/dist/block_storage_vm.cjs +264 -0
  26. package/dist/block_storage_vm.cjs.map +1 -0
  27. package/dist/block_storage_vm.d.ts +67 -0
  28. package/dist/block_storage_vm.d.ts.map +1 -0
  29. package/dist/block_storage_vm.js +260 -0
  30. package/dist/block_storage_vm.js.map +1 -0
  31. package/dist/builder.cjs +9 -6
  32. package/dist/builder.cjs.map +1 -1
  33. package/dist/builder.d.ts +15 -30
  34. package/dist/builder.d.ts.map +1 -1
  35. package/dist/builder.js +10 -7
  36. package/dist/builder.js.map +1 -1
  37. package/dist/components/PlDataTable.cjs.map +1 -1
  38. package/dist/components/PlDataTable.d.ts +2 -2
  39. package/dist/components/PlDataTable.d.ts.map +1 -1
  40. package/dist/components/PlDataTable.js.map +1 -1
  41. package/dist/index.cjs +25 -0
  42. package/dist/index.cjs.map +1 -1
  43. package/dist/index.d.ts +3 -0
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +4 -1
  46. package/dist/index.js.map +1 -1
  47. package/dist/internal.cjs +38 -0
  48. package/dist/internal.cjs.map +1 -1
  49. package/dist/internal.d.ts +21 -0
  50. package/dist/internal.d.ts.map +1 -1
  51. package/dist/internal.js +36 -1
  52. package/dist/internal.js.map +1 -1
  53. package/dist/package.json.cjs +1 -1
  54. package/dist/package.json.js +1 -1
  55. package/dist/platforma.d.ts +18 -3
  56. package/dist/platforma.d.ts.map +1 -1
  57. package/dist/render/api.cjs +43 -16
  58. package/dist/render/api.cjs.map +1 -1
  59. package/dist/render/api.d.ts +19 -7
  60. package/dist/render/api.d.ts.map +1 -1
  61. package/dist/render/api.js +42 -17
  62. package/dist/render/api.js.map +1 -1
  63. package/dist/render/internal.cjs.map +1 -1
  64. package/dist/render/internal.d.ts +3 -1
  65. package/dist/render/internal.d.ts.map +1 -1
  66. package/dist/render/internal.js.map +1 -1
  67. package/dist/render/util/label.cjs +9 -4
  68. package/dist/render/util/label.cjs.map +1 -1
  69. package/dist/render/util/label.d.ts.map +1 -1
  70. package/dist/render/util/label.js +9 -4
  71. package/dist/render/util/label.js.map +1 -1
  72. package/package.json +5 -5
  73. package/src/bconfig/lambdas.ts +35 -4
  74. package/src/bconfig/v3.ts +12 -2
  75. package/src/block_api_v3.ts +49 -0
  76. package/src/block_migrations.ts +173 -0
  77. package/src/block_model.ts +440 -0
  78. package/src/block_storage.test.ts +258 -0
  79. package/src/block_storage.ts +365 -0
  80. package/src/block_storage_vm.ts +349 -0
  81. package/src/builder.ts +24 -59
  82. package/src/components/PlDataTable.ts +2 -1
  83. package/src/index.ts +3 -0
  84. package/src/internal.ts +51 -0
  85. package/src/platforma.ts +31 -5
  86. package/src/render/api.ts +52 -21
  87. package/src/render/internal.ts +3 -1
  88. package/src/render/util/label.test.ts +25 -0
  89. package/src/render/util/label.ts +11 -5
@@ -1 +1 @@
1
- {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/render/internal.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/render/internal.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"internal.js","sources":["../../src/render/internal.ts"],"sourcesContent":["import type { Optional } from 'utility-types';\nimport type { Branded } from '../branding';\nimport type { CommonFieldTraverseOps, FieldTraversalStep, ResourceType } from './traversal_ops';\nimport type {\n ArchiveFormat,\n AnyFunction,\n Option,\n PColumn,\n PColumnValues,\n PFrameDef,\n PFrameHandle,\n PObject,\n PObjectSpec,\n PSpecPredicate,\n PTableDef,\n PTableHandle,\n ResultCollection,\n ValueOrError,\n DataInfo,\n RangeBytes,\n} from '@milaboratories/pl-model-common';\n\nexport const StagingAccessorName = 'staging';\nexport const MainAccessorName = 'main';\n\nexport type AccessorHandle = Branded<string, 'AccessorHandle'>;\nexport type FutureHandle = Branded<string, 'FutureHandle'>;\n\nexport interface GlobalCfgRenderCtxMethods<AHandle = AccessorHandle, FHandle = FutureHandle> {\n\n //\n // Root accessor creation\n //\n\n getAccessorHandleByName(name: string): AHandle | undefined;\n\n //\n // Basic resource accessor actions\n //\n\n resolveWithCommon(\n handle: AHandle,\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): AHandle | undefined;\n\n getResourceType(handle: AHandle): ResourceType;\n\n getInputsLocked(handle: AHandle): boolean;\n\n getOutputsLocked(handle: AHandle): boolean;\n\n getIsReadyOrError(handle: AHandle): boolean;\n\n getIsFinal(handle: AHandle): boolean;\n\n getError(handle: AHandle): AHandle | undefined;\n\n listInputFields(handle: AHandle): string[];\n\n listOutputFields(handle: AHandle): string[];\n\n listDynamicFields(handle: AHandle): string[];\n\n getKeyValueBase64(handle: AHandle, key: string): string | undefined;\n\n getKeyValueAsString(handle: AHandle, key: string): string | undefined;\n\n getDataBase64(handle: AHandle): string | undefined;\n\n getDataAsString(handle: AHandle): string | undefined;\n\n /** If not final returns undefined */\n parsePObjectCollection(\n handle: AHandle,\n errorOnUnknownField: boolean,\n prefix: string,\n ...resolvePath: string[]\n ): Record<string, PObject<AHandle>> | undefined;\n\n //\n // Blob\n //\n\n getBlobContentAsBase64(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getBlobContentAsString(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getDownloadedBlobContentHandle(handle: AHandle): FHandle; // LocalBlobHandleAndSize | undefined;\n\n getOnDemandBlobContentHandle(handle: AHandle): FHandle; // RemoteBlobHandleAndSize | undefined;\n\n //\n // Blobs to URLs\n //\n\n extractArchiveAndGetURL(handle: AHandle, format: ArchiveFormat): FHandle;\n\n //\n // Import progress\n //\n\n getImportProgress(handle: AHandle): FHandle; // ImportProgress;\n\n //\n // Logs\n //\n\n getLastLogs(handle: AHandle, nLines: number): FHandle; // string | undefined;\n\n getProgressLog(handle: AHandle, patternToSearch: string): FHandle; // string | undefined;\n\n getProgressLogWithInfo(handle: AHandle, patternToSearch: string): FHandle; // ProgressLogWithInfo | undefined;\n\n getLogHandle(handle: AHandle): FHandle; // AnyLogHandle | undefined;\n\n //\n // Blocks\n //\n\n /** @deprecated at some point will stop working and will return dummy values */\n getBlockLabel(blockId: string): string;\n\n //\n // Result Pool\n //\n\n getDataFromResultPool(): ResultCollection<PObject<AHandle>>;\n\n getDataWithErrorsFromResultPool(): ResultCollection<\n Optional<PObject<ValueOrError<AHandle, Error>>, 'id'>\n >;\n\n getSpecsFromResultPool(): ResultCollection<PObjectSpec>;\n\n getSpecFromResultPoolByRef(blockId: string, exportName: string): PObjectSpec | undefined;\n\n getDataFromResultPoolByRef(blockId: string, exportName: string): PObject<AHandle> | undefined;\n\n calculateOptions(predicate: PSpecPredicate): Option[];\n\n //\n // PFrame / PTable\n //\n\n createPFrame(def: PFrameDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PFrameHandle;\n\n createPTable(def: PTableDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PTableHandle;\n\n //\n // Computable\n //\n\n getCurrentUnstableMarker(): string | undefined;\n\n //\n // Logging\n //\n\n logInfo(message: string): void;\n\n logWarn(message: string): void;\n\n logError(message: string): void;\n}\n\nexport const GlobalCfgRenderCtxFeatureFlags = {\n explicitColumnsSupport: true as const,\n inlineColumnsSupport: true as const,\n activeArgs: true as const,\n pTablePartitionFiltersSupport: true as const,\n pFrameInSetFilterSupport: true as const,\n};\n\nexport interface GlobalCfgRenderCtx extends GlobalCfgRenderCtxMethods {\n //\n // State: Args, UI State, Active Args\n //\n // Old runtime injects these values as strings, new runtime injects them as functions\n // that return strings, if block declares supportsLazyState flag.\n // If function not called in lazy state API, then resulting output will not depend on these values,\n // and thus will not be recalculated on corresponding state change.\n //\n\n readonly args: string | (() => string);\n readonly uiState: string | (() => string);\n readonly activeArgs: undefined | string | (() => string | undefined);\n\n // Note: strings below are used because, anyway, using strings is the only way\n // to get data inside the QuickJS context, as it is implemented now. With this\n // approach deserialization can be lazily postponed until it is actually needed.\n readonly callbackRegistry: Record<string, AnyFunction>;\n readonly featureFlags?: typeof GlobalCfgRenderCtxFeatureFlags;\n}\n\nexport type FutureAwait = {\n __awaited_futures__: FutureHandle[];\n};\n\nexport function isFutureAwait(obj: unknown): obj is FutureAwait {\n return typeof obj === 'object' && obj !== null && '__awaited_futures__' in obj;\n}\n\nfunction addAllFutureAwaits(set: Set<string>, visited: Set<unknown>, node: unknown) {\n if (visited.has(node)) return;\n visited.add(node);\n\n const type = typeof node;\n if (type === 'object') {\n if (isFutureAwait(node)) node.__awaited_futures__.forEach((a) => set.add(a));\n else if (Array.isArray(node))\n for (const nested of node) addAllFutureAwaits(set, visited, nested);\n else\n for (const [, nested] of Object.entries(node as object))\n if (nested !== node) addAllFutureAwaits(set, visited, nested);\n }\n}\n\nexport function getAllFutureAwaits(obj: unknown): Set<string> {\n const set = new Set<string>();\n addAllFutureAwaits(set, new Set(), obj);\n return set;\n}\n"],"names":[],"mappings":"AAsBO,MAAM,mBAAmB,GAAG;AAC5B,MAAM,gBAAgB,GAAG;AA+IzB,MAAM,8BAA8B,GAAG;AAC5C,IAAA,sBAAsB,EAAE,IAAa;AACrC,IAAA,oBAAoB,EAAE,IAAa;AACnC,IAAA,UAAU,EAAE,IAAa;AACzB,IAAA,6BAA6B,EAAE,IAAa;AAC5C,IAAA,wBAAwB,EAAE,IAAa;;AA4BnC,SAAU,aAAa,CAAC,GAAY,EAAA;AACxC,IAAA,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,qBAAqB,IAAI,GAAG;AAChF;AAEA,SAAS,kBAAkB,CAAC,GAAgB,EAAE,OAAqB,EAAE,IAAa,EAAA;AAChF,IAAA,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE;AACvB,IAAA,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAEjB,IAAA,MAAM,IAAI,GAAG,OAAO,IAAI;AACxB,IAAA,IAAI,IAAI,KAAK,QAAQ,EAAE;QACrB,IAAI,aAAa,CAAC,IAAI,CAAC;AAAE,YAAA,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACvE,aAAA,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAC1B,KAAK,MAAM,MAAM,IAAI,IAAI;AAAE,gBAAA,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC;;YAEnE,KAAK,MAAM,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAc,CAAC;gBACrD,IAAI,MAAM,KAAK,IAAI;AAAE,oBAAA,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC;IACnE;AACF;AAEM,SAAU,kBAAkB,CAAC,GAAY,EAAA;AAC7C,IAAA,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU;IAC7B,kBAAkB,CAAC,GAAG,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,CAAC;AACvC,IAAA,OAAO,GAAG;AACZ;;;;"}
1
+ {"version":3,"file":"internal.js","sources":["../../src/render/internal.ts"],"sourcesContent":["import type { Optional } from 'utility-types';\nimport type { Branded } from '../branding';\nimport type { CommonFieldTraverseOps, FieldTraversalStep, ResourceType } from './traversal_ops';\nimport type {\n ArchiveFormat,\n AnyFunction,\n Option,\n PColumn,\n PColumnValues,\n PFrameDef,\n PFrameHandle,\n PObject,\n PObjectSpec,\n PSpecPredicate,\n PTableDef,\n PTableHandle,\n ResultCollection,\n ValueOrError,\n DataInfo,\n RangeBytes,\n} from '@milaboratories/pl-model-common';\n\nexport const StagingAccessorName = 'staging';\nexport const MainAccessorName = 'main';\n\nexport type AccessorHandle = Branded<string, 'AccessorHandle'>;\nexport type FutureHandle = Branded<string, 'FutureHandle'>;\n\nexport interface GlobalCfgRenderCtxMethods<AHandle = AccessorHandle, FHandle = FutureHandle> {\n\n //\n // Root accessor creation\n //\n\n getAccessorHandleByName(name: string): AHandle | undefined;\n\n //\n // Basic resource accessor actions\n //\n\n resolveWithCommon(\n handle: AHandle,\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): AHandle | undefined;\n\n getResourceType(handle: AHandle): ResourceType;\n\n getInputsLocked(handle: AHandle): boolean;\n\n getOutputsLocked(handle: AHandle): boolean;\n\n getIsReadyOrError(handle: AHandle): boolean;\n\n getIsFinal(handle: AHandle): boolean;\n\n getError(handle: AHandle): AHandle | undefined;\n\n listInputFields(handle: AHandle): string[];\n\n listOutputFields(handle: AHandle): string[];\n\n listDynamicFields(handle: AHandle): string[];\n\n getKeyValueBase64(handle: AHandle, key: string): string | undefined;\n\n getKeyValueAsString(handle: AHandle, key: string): string | undefined;\n\n getDataBase64(handle: AHandle): string | undefined;\n\n getDataAsString(handle: AHandle): string | undefined;\n\n /** If not final returns undefined */\n parsePObjectCollection(\n handle: AHandle,\n errorOnUnknownField: boolean,\n prefix: string,\n ...resolvePath: string[]\n ): Record<string, PObject<AHandle>> | undefined;\n\n //\n // Blob\n //\n\n getBlobContentAsBase64(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getBlobContentAsString(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getDownloadedBlobContentHandle(handle: AHandle): FHandle; // LocalBlobHandleAndSize | undefined;\n\n getOnDemandBlobContentHandle(handle: AHandle): FHandle; // RemoteBlobHandleAndSize | undefined;\n\n //\n // Blobs to URLs\n //\n\n extractArchiveAndGetURL(handle: AHandle, format: ArchiveFormat): FHandle;\n\n //\n // Import progress\n //\n\n getImportProgress(handle: AHandle): FHandle; // ImportProgress;\n\n //\n // Logs\n //\n\n getLastLogs(handle: AHandle, nLines: number): FHandle; // string | undefined;\n\n getProgressLog(handle: AHandle, patternToSearch: string): FHandle; // string | undefined;\n\n getProgressLogWithInfo(handle: AHandle, patternToSearch: string): FHandle; // ProgressLogWithInfo | undefined;\n\n getLogHandle(handle: AHandle): FHandle; // AnyLogHandle | undefined;\n\n //\n // Blocks\n //\n\n /** @deprecated at some point will stop working and will return dummy values */\n getBlockLabel(blockId: string): string;\n\n //\n // Result Pool\n //\n\n getDataFromResultPool(): ResultCollection<PObject<AHandle>>;\n\n getDataWithErrorsFromResultPool(): ResultCollection<\n Optional<PObject<ValueOrError<AHandle, Error>>, 'id'>\n >;\n\n getSpecsFromResultPool(): ResultCollection<PObjectSpec>;\n\n getSpecFromResultPoolByRef(blockId: string, exportName: string): PObjectSpec | undefined;\n\n getDataFromResultPoolByRef(blockId: string, exportName: string): PObject<AHandle> | undefined;\n\n calculateOptions(predicate: PSpecPredicate): Option[];\n\n //\n // PFrame / PTable\n //\n\n createPFrame(def: PFrameDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PFrameHandle;\n\n createPTable(def: PTableDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PTableHandle;\n\n //\n // Computable\n //\n\n getCurrentUnstableMarker(): string | undefined;\n\n //\n // Logging\n //\n\n logInfo(message: string): void;\n\n logWarn(message: string): void;\n\n logError(message: string): void;\n}\n\nexport const GlobalCfgRenderCtxFeatureFlags = {\n explicitColumnsSupport: true as const,\n inlineColumnsSupport: true as const,\n activeArgs: true as const,\n pTablePartitionFiltersSupport: true as const,\n pFrameInSetFilterSupport: true as const,\n};\n\nexport interface GlobalCfgRenderCtx extends GlobalCfgRenderCtxMethods {\n //\n // State: Args, UI State, Active Args\n //\n // Old runtime injects these values as strings, new runtime injects them as functions\n // that return strings, if block declares supportsLazyState flag.\n // If function not called in lazy state API, then resulting output will not depend on these values,\n // and thus will not be recalculated on corresponding state change.\n //\n\n readonly args: string | (() => string);\n /** @deprecated Use `data` instead. Optional for backward compatibility - falls back to `data` if not injected. */\n readonly uiState?: string | (() => string);\n readonly data: string | (() => string);\n readonly activeArgs: undefined | string | (() => string | undefined);\n\n // Note: strings below are used because, anyway, using strings is the only way\n // to get data inside the QuickJS context, as it is implemented now. With this\n // approach deserialization can be lazily postponed until it is actually needed.\n readonly callbackRegistry: Record<string, AnyFunction>;\n readonly featureFlags?: typeof GlobalCfgRenderCtxFeatureFlags;\n}\n\nexport type FutureAwait = {\n __awaited_futures__: FutureHandle[];\n};\n\nexport function isFutureAwait(obj: unknown): obj is FutureAwait {\n return typeof obj === 'object' && obj !== null && '__awaited_futures__' in obj;\n}\n\nfunction addAllFutureAwaits(set: Set<string>, visited: Set<unknown>, node: unknown) {\n if (visited.has(node)) return;\n visited.add(node);\n\n const type = typeof node;\n if (type === 'object') {\n if (isFutureAwait(node)) node.__awaited_futures__.forEach((a) => set.add(a));\n else if (Array.isArray(node))\n for (const nested of node) addAllFutureAwaits(set, visited, nested);\n else\n for (const [, nested] of Object.entries(node as object))\n if (nested !== node) addAllFutureAwaits(set, visited, nested);\n }\n}\n\nexport function getAllFutureAwaits(obj: unknown): Set<string> {\n const set = new Set<string>();\n addAllFutureAwaits(set, new Set(), obj);\n return set;\n}\n"],"names":[],"mappings":"AAsBO,MAAM,mBAAmB,GAAG;AAC5B,MAAM,gBAAgB,GAAG;AA+IzB,MAAM,8BAA8B,GAAG;AAC5C,IAAA,sBAAsB,EAAE,IAAa;AACrC,IAAA,oBAAoB,EAAE,IAAa;AACnC,IAAA,UAAU,EAAE,IAAa;AACzB,IAAA,6BAA6B,EAAE,IAAa;AAC5C,IAAA,wBAAwB,EAAE,IAAa;;AA8BnC,SAAU,aAAa,CAAC,GAAY,EAAA;AACxC,IAAA,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,qBAAqB,IAAI,GAAG;AAChF;AAEA,SAAS,kBAAkB,CAAC,GAAgB,EAAE,OAAqB,EAAE,IAAa,EAAA;AAChF,IAAA,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE;AACvB,IAAA,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAEjB,IAAA,MAAM,IAAI,GAAG,OAAO,IAAI;AACxB,IAAA,IAAI,IAAI,KAAK,QAAQ,EAAE;QACrB,IAAI,aAAa,CAAC,IAAI,CAAC;AAAE,YAAA,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACvE,aAAA,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAC1B,KAAK,MAAM,MAAM,IAAI,IAAI;AAAE,gBAAA,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC;;YAEnE,KAAK,MAAM,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAc,CAAC;gBACrD,IAAI,MAAM,KAAK,IAAI;AAAE,oBAAA,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC;IACnE;AACF;AAEM,SAAU,kBAAkB,CAAC,GAAY,EAAA;AAC7C,IAAA,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU;IAC7B,kBAAkB,CAAC,GAAG,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,CAAC;AACvC,IAAA,OAAO,GAAG;AACZ;;;;"}
@@ -110,10 +110,15 @@ function deriveLabels(values, specExtractor, ops = {}) {
110
110
  }
111
111
  return result;
112
112
  };
113
- // Checks if a result has all unique labels
114
- const hasUniqueLabels = (result) => result !== undefined && new Set(result.map((c) => c.label)).size === values.length;
113
+ const countUniqueLabels = (result) => result === undefined ? 0 : new Set(result.map((c) => c.label)).size;
115
114
  // Post-processing: try removing types one by one (lowest importance first) to minimize the label set
115
+ // Accepts removal if it doesn't decrease the number of unique labels (cardinality)
116
116
  const minimizeTypeSet = (typeSet) => {
117
+ const initialResult = calculate(typeSet);
118
+ if (initialResult === undefined) {
119
+ return typeSet;
120
+ }
121
+ const currentCardinality = countUniqueLabels(initialResult);
117
122
  // Get types sorted by importance ascending (lowest first), excluding forced elements
118
123
  const removableSorted = [...typeSet]
119
124
  .filter((t) => !forceTraceElements?.has(t.split('@')[0])
@@ -123,7 +128,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
123
128
  const reducedSet = new Set(typeSet);
124
129
  reducedSet.delete(typeToRemove);
125
130
  const candidateResult = calculate(reducedSet);
126
- if (hasUniqueLabels(candidateResult)) {
131
+ if (candidateResult !== undefined && countUniqueLabels(candidateResult) >= currentCardinality) {
127
132
  typeSet.delete(typeToRemove);
128
133
  }
129
134
  }
@@ -154,7 +159,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
154
159
  if (additionalType >= 0)
155
160
  currentSet.add(mainTypes[additionalType]);
156
161
  const candidateResult = calculate(currentSet);
157
- if (hasUniqueLabels(candidateResult)) {
162
+ if (candidateResult !== undefined && countUniqueLabels(candidateResult) === values.length) {
158
163
  minimizeTypeSet(currentSet);
159
164
  return calculate(currentSet);
160
165
  }
@@ -1 +1 @@
1
- {"version":3,"file":"label.cjs","sources":["../../../src/render/util/label.ts"],"sourcesContent":["import { Annotation, parseJson, readAnnotation, type PObjectSpec } from '@milaboratories/pl-model-common';\nimport { z } from 'zod';\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult = PObjectSpec | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n};\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = '__LABEL__';\nconst LabelTypeFull = '__LABEL__@1';\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements = (ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0)\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if ('spec' in extractorResult && typeof extractorResult.spec === 'object') {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = readAnnotation(spec, Annotation.Label);\n const traceStr = readAnnotation(spec, Annotation.Trace);\n const baseTrace = (traceStr ? Trace.safeParse(parseJson(traceStr)).data : undefined) ?? [];\n\n const trace = [\n ...(prefixTrace ?? []),\n ...baseTrace,\n ...(suffixTrace ?? []),\n ];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith('@1') || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace\n .filter((fm) => includedTypes.has(fm.fullType)\n || (forceTraceElements && forceTraceElements.has(fm.type)));\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: 'Unlabeled',\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace\n .map((fm) => fm.label);\n const sep = ops.separator ?? ' / ';\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n // Checks if a result has all unique labels\n const hasUniqueLabels = (result: RecordsWithLabel<T>[] | undefined): boolean =>\n result !== undefined && new Set(result.map((c) => c.label)).size === values.length;\n\n // Post-processing: try removing types one by one (lowest importance first) to minimize the label set\n const minimizeTypeSet = (typeSet: Set<string>): Set<string> => {\n // Get types sorted by importance ascending (lowest first), excluding forced elements\n const removableSorted = [...typeSet]\n .filter((t) =>\n !forceTraceElements?.has(t.split('@')[0])\n && !(ops.includeNativeLabel && t === LabelTypeFull))\n .sort((a, b) => (importances.get(a) ?? 0) - (importances.get(b) ?? 0));\n\n for (const typeToRemove of removableSorted) {\n const reducedSet = new Set(typeSet);\n reducedSet.delete(typeToRemove);\n const candidateResult = calculate(reducedSet);\n if (hasUniqueLabels(candidateResult)) {\n typeSet.delete(typeToRemove);\n }\n }\n return typeSet;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0) throw new Error('Non-empty secondary types list while main types list is empty.');\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0)\n currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n if (hasUniqueLabels(candidateResult)) {\n minimizeTypeSet(currentSet);\n return calculate(currentSet)!;\n }\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n // Fallback: include all types, then try to minimize\n const fallbackSet = new Set([...mainTypes, ...secondaryTypes]);\n minimizeTypeSet(fallbackSet);\n return calculate(fallbackSet, true)!;\n}\n"],"names":["z","readAnnotation","Annotation","parseJson"],"mappings":"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"}
1
+ {"version":3,"file":"label.cjs","sources":["../../../src/render/util/label.ts"],"sourcesContent":["import { Annotation, parseJson, readAnnotation, type PObjectSpec } from '@milaboratories/pl-model-common';\nimport { z } from 'zod';\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult = PObjectSpec | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n};\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = '__LABEL__';\nconst LabelTypeFull = '__LABEL__@1';\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements = (ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0)\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if ('spec' in extractorResult && typeof extractorResult.spec === 'object') {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = readAnnotation(spec, Annotation.Label);\n const traceStr = readAnnotation(spec, Annotation.Trace);\n const baseTrace = (traceStr ? Trace.safeParse(parseJson(traceStr)).data : undefined) ?? [];\n\n const trace = [\n ...(prefixTrace ?? []),\n ...baseTrace,\n ...(suffixTrace ?? []),\n ];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith('@1') || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace\n .filter((fm) => includedTypes.has(fm.fullType)\n || (forceTraceElements && forceTraceElements.has(fm.type)));\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: 'Unlabeled',\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace\n .map((fm) => fm.label);\n const sep = ops.separator ?? ' / ';\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n const countUniqueLabels = (result: RecordsWithLabel<T>[] | undefined): number =>\n result === undefined ? 0 : new Set(result.map((c) => c.label)).size;\n\n // Post-processing: try removing types one by one (lowest importance first) to minimize the label set\n // Accepts removal if it doesn't decrease the number of unique labels (cardinality)\n const minimizeTypeSet = (typeSet: Set<string>): Set<string> => {\n const initialResult = calculate(typeSet);\n if (initialResult === undefined) {\n return typeSet;\n }\n const currentCardinality = countUniqueLabels(initialResult);\n\n // Get types sorted by importance ascending (lowest first), excluding forced elements\n const removableSorted = [...typeSet]\n .filter((t) =>\n !forceTraceElements?.has(t.split('@')[0])\n && !(ops.includeNativeLabel && t === LabelTypeFull))\n .sort((a, b) => (importances.get(a) ?? 0) - (importances.get(b) ?? 0));\n\n for (const typeToRemove of removableSorted) {\n const reducedSet = new Set(typeSet);\n reducedSet.delete(typeToRemove);\n const candidateResult = calculate(reducedSet);\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) >= currentCardinality) {\n typeSet.delete(typeToRemove);\n }\n }\n return typeSet;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0) throw new Error('Non-empty secondary types list while main types list is empty.');\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0)\n currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) === values.length) {\n minimizeTypeSet(currentSet);\n return calculate(currentSet)!;\n }\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n // Fallback: include all types, then try to minimize\n const fallbackSet = new Set([...mainTypes, ...secondaryTypes]);\n minimizeTypeSet(fallbackSet);\n return calculate(fallbackSet, true)!;\n}\n"],"names":["z","readAnnotation","Annotation","parseJson"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../src/render/util/label.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyC,KAAK,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC1G,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAChC,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sHAAsH;IACtH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;EAKrB,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAGpD,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;WAAsB,CAAC;AACzC,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAI1C,KAAK,mBAAmB,GAAG,WAAW,GAAG;IACvC,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;CAC5B,CAAC;AAOF,wBAAgB,YAAY,CAAC,CAAC,EAC5B,MAAM,EAAE,CAAC,EAAE,EACX,aAAa,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,mBAAmB,EAC9C,GAAG,GAAE,kBAAuB,GAC3B,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAiLvB"}
1
+ {"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../src/render/util/label.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyC,KAAK,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC1G,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAChC,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sHAAsH;IACtH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;EAKrB,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAGpD,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;WAAsB,CAAC;AACzC,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAI1C,KAAK,mBAAmB,GAAG,WAAW,GAAG;IACvC,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;CAC5B,CAAC;AAOF,wBAAgB,YAAY,CAAC,CAAC,EAC5B,MAAM,EAAE,CAAC,EAAE,EACX,aAAa,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,mBAAmB,EAC9C,GAAG,GAAE,kBAAuB,GAC3B,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAuLvB"}
@@ -108,10 +108,15 @@ function deriveLabels(values, specExtractor, ops = {}) {
108
108
  }
109
109
  return result;
110
110
  };
111
- // Checks if a result has all unique labels
112
- const hasUniqueLabels = (result) => result !== undefined && new Set(result.map((c) => c.label)).size === values.length;
111
+ const countUniqueLabels = (result) => result === undefined ? 0 : new Set(result.map((c) => c.label)).size;
113
112
  // Post-processing: try removing types one by one (lowest importance first) to minimize the label set
113
+ // Accepts removal if it doesn't decrease the number of unique labels (cardinality)
114
114
  const minimizeTypeSet = (typeSet) => {
115
+ const initialResult = calculate(typeSet);
116
+ if (initialResult === undefined) {
117
+ return typeSet;
118
+ }
119
+ const currentCardinality = countUniqueLabels(initialResult);
115
120
  // Get types sorted by importance ascending (lowest first), excluding forced elements
116
121
  const removableSorted = [...typeSet]
117
122
  .filter((t) => !forceTraceElements?.has(t.split('@')[0])
@@ -121,7 +126,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
121
126
  const reducedSet = new Set(typeSet);
122
127
  reducedSet.delete(typeToRemove);
123
128
  const candidateResult = calculate(reducedSet);
124
- if (hasUniqueLabels(candidateResult)) {
129
+ if (candidateResult !== undefined && countUniqueLabels(candidateResult) >= currentCardinality) {
125
130
  typeSet.delete(typeToRemove);
126
131
  }
127
132
  }
@@ -152,7 +157,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
152
157
  if (additionalType >= 0)
153
158
  currentSet.add(mainTypes[additionalType]);
154
159
  const candidateResult = calculate(currentSet);
155
- if (hasUniqueLabels(candidateResult)) {
160
+ if (candidateResult !== undefined && countUniqueLabels(candidateResult) === values.length) {
156
161
  minimizeTypeSet(currentSet);
157
162
  return calculate(currentSet);
158
163
  }
@@ -1 +1 @@
1
- {"version":3,"file":"label.js","sources":["../../../src/render/util/label.ts"],"sourcesContent":["import { Annotation, parseJson, readAnnotation, type PObjectSpec } from '@milaboratories/pl-model-common';\nimport { z } from 'zod';\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult = PObjectSpec | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n};\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = '__LABEL__';\nconst LabelTypeFull = '__LABEL__@1';\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements = (ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0)\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if ('spec' in extractorResult && typeof extractorResult.spec === 'object') {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = readAnnotation(spec, Annotation.Label);\n const traceStr = readAnnotation(spec, Annotation.Trace);\n const baseTrace = (traceStr ? Trace.safeParse(parseJson(traceStr)).data : undefined) ?? [];\n\n const trace = [\n ...(prefixTrace ?? []),\n ...baseTrace,\n ...(suffixTrace ?? []),\n ];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith('@1') || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace\n .filter((fm) => includedTypes.has(fm.fullType)\n || (forceTraceElements && forceTraceElements.has(fm.type)));\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: 'Unlabeled',\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace\n .map((fm) => fm.label);\n const sep = ops.separator ?? ' / ';\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n // Checks if a result has all unique labels\n const hasUniqueLabels = (result: RecordsWithLabel<T>[] | undefined): boolean =>\n result !== undefined && new Set(result.map((c) => c.label)).size === values.length;\n\n // Post-processing: try removing types one by one (lowest importance first) to minimize the label set\n const minimizeTypeSet = (typeSet: Set<string>): Set<string> => {\n // Get types sorted by importance ascending (lowest first), excluding forced elements\n const removableSorted = [...typeSet]\n .filter((t) =>\n !forceTraceElements?.has(t.split('@')[0])\n && !(ops.includeNativeLabel && t === LabelTypeFull))\n .sort((a, b) => (importances.get(a) ?? 0) - (importances.get(b) ?? 0));\n\n for (const typeToRemove of removableSorted) {\n const reducedSet = new Set(typeSet);\n reducedSet.delete(typeToRemove);\n const candidateResult = calculate(reducedSet);\n if (hasUniqueLabels(candidateResult)) {\n typeSet.delete(typeToRemove);\n }\n }\n return typeSet;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0) throw new Error('Non-empty secondary types list while main types list is empty.');\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0)\n currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n if (hasUniqueLabels(candidateResult)) {\n minimizeTypeSet(currentSet);\n return calculate(currentSet)!;\n }\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n // Fallback: include all types, then try to minimize\n const fallbackSet = new Set([...mainTypes, ...secondaryTypes]);\n minimizeTypeSet(fallbackSet);\n return calculate(fallbackSet, true)!;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"label.js","sources":["../../../src/render/util/label.ts"],"sourcesContent":["import { Annotation, parseJson, readAnnotation, type PObjectSpec } from '@milaboratories/pl-model-common';\nimport { z } from 'zod';\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult = PObjectSpec | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n};\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = '__LABEL__';\nconst LabelTypeFull = '__LABEL__@1';\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements = (ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0)\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if ('spec' in extractorResult && typeof extractorResult.spec === 'object') {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = readAnnotation(spec, Annotation.Label);\n const traceStr = readAnnotation(spec, Annotation.Trace);\n const baseTrace = (traceStr ? Trace.safeParse(parseJson(traceStr)).data : undefined) ?? [];\n\n const trace = [\n ...(prefixTrace ?? []),\n ...baseTrace,\n ...(suffixTrace ?? []),\n ];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith('@1') || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace\n .filter((fm) => includedTypes.has(fm.fullType)\n || (forceTraceElements && forceTraceElements.has(fm.type)));\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: 'Unlabeled',\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace\n .map((fm) => fm.label);\n const sep = ops.separator ?? ' / ';\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n const countUniqueLabels = (result: RecordsWithLabel<T>[] | undefined): number =>\n result === undefined ? 0 : new Set(result.map((c) => c.label)).size;\n\n // Post-processing: try removing types one by one (lowest importance first) to minimize the label set\n // Accepts removal if it doesn't decrease the number of unique labels (cardinality)\n const minimizeTypeSet = (typeSet: Set<string>): Set<string> => {\n const initialResult = calculate(typeSet);\n if (initialResult === undefined) {\n return typeSet;\n }\n const currentCardinality = countUniqueLabels(initialResult);\n\n // Get types sorted by importance ascending (lowest first), excluding forced elements\n const removableSorted = [...typeSet]\n .filter((t) =>\n !forceTraceElements?.has(t.split('@')[0])\n && !(ops.includeNativeLabel && t === LabelTypeFull))\n .sort((a, b) => (importances.get(a) ?? 0) - (importances.get(b) ?? 0));\n\n for (const typeToRemove of removableSorted) {\n const reducedSet = new Set(typeSet);\n reducedSet.delete(typeToRemove);\n const candidateResult = calculate(reducedSet);\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) >= currentCardinality) {\n typeSet.delete(typeToRemove);\n }\n }\n return typeSet;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0) throw new Error('Non-empty secondary types list while main types list is empty.');\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0)\n currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) === values.length) {\n minimizeTypeSet(currentSet);\n return calculate(currentSet)!;\n }\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n // Fallback: include all types, then try to minimize\n const fallbackSet = new Set([...mainTypes, ...secondaryTypes]);\n minimizeTypeSet(fallbackSet);\n return calculate(fallbackSet, true)!;\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/model",
3
- "version": "1.51.6",
3
+ "version": "1.52.0",
4
4
  "description": "Platforma.bio SDK / Block Model",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -23,18 +23,18 @@
23
23
  "canonicalize": "~2.1.0",
24
24
  "es-toolkit": "^1.39.10",
25
25
  "zod": "~3.23.8",
26
- "@milaboratories/ptabler-expression-js": "1.1.9",
27
- "@milaboratories/pl-model-common": "1.23.0",
28
- "@milaboratories/pl-error-like": "1.12.5"
26
+ "@milaboratories/pl-error-like": "1.12.5",
27
+ "@milaboratories/pl-model-common": "1.24.0",
28
+ "@milaboratories/ptabler-expression-js": "1.1.10"
29
29
  },
30
30
  "devDependencies": {
31
31
  "typescript": "~5.6.3",
32
32
  "vitest": "^4.0.16",
33
33
  "@vitest/coverage-istanbul": "^4.0.16",
34
34
  "fast-json-patch": "^3.1.1",
35
- "@milaboratories/eslint-config": "1.0.5",
36
35
  "@milaboratories/build-configs": "1.2.2",
37
36
  "@milaboratories/ts-builder": "1.2.2",
37
+ "@milaboratories/eslint-config": "1.0.5",
38
38
  "@milaboratories/ts-configs": "1.2.0",
39
39
  "@milaboratories/helpers": "1.13.0"
40
40
  },
@@ -1,12 +1,16 @@
1
1
  import type { ConfigResult, PlResourceEntry, TypedConfig } from '../config';
2
+ import type { OutputWithStatus } from '@milaboratories/pl-model-common';
3
+ import type { TypedConfigOrConfigLambda } from './types';
2
4
 
3
- export type StdCtxArgsOnly<Args, UiState = undefined> = {
5
+ export type StdCtxArgsOnly<Args, Data = undefined> = {
4
6
  readonly $blockId: string;
5
7
  readonly $args: Args;
6
- readonly $ui: UiState;
8
+ /** @deprecated Use $data instead. Kept for V1/V2 block compatibility. */
9
+ readonly $ui: Data;
10
+ readonly $data: Data;
7
11
  };
8
12
 
9
- export type StdCtx<Args, UiState = undefined> = StdCtxArgsOnly<Args, UiState> & {
13
+ export type StdCtx<Args, Data = undefined> = StdCtxArgsOnly<Args, Data> & {
10
14
  readonly $prod: PlResourceEntry;
11
15
  readonly $staging: PlResourceEntry;
12
16
  };
@@ -20,7 +24,7 @@ export type ResolveCfgType<Cfg extends TypedConfig, Args, UiState = undefined> =
20
24
  export type ConfigRenderLambdaFlags = {
21
25
  /**
22
26
  * Tells the system that corresponding computable should be created with StableOnlyRetentive rendering mode.
23
- * This flag can be overriden by the system.
27
+ * This flag can be overridden by the system.
24
28
  * */
25
29
  retentive?: boolean;
26
30
 
@@ -51,3 +55,30 @@ export interface ConfigRenderLambda<Return = unknown> extends ConfigRenderLambda
51
55
 
52
56
  export type ExtractFunctionHandleReturn<Func extends ConfigRenderLambda> =
53
57
  Func extends ConfigRenderLambda<infer Return> ? Return : never;
58
+
59
+ /** Infers the output type from a TypedConfig or ConfigRenderLambda */
60
+ export type InferOutputType<CfgOrFH, Args, UiState> = CfgOrFH extends TypedConfig
61
+ ? ResolveCfgType<CfgOrFH, Args, UiState>
62
+ : CfgOrFH extends ConfigRenderLambda
63
+ ? ExtractFunctionHandleReturn<CfgOrFH>
64
+ : never;
65
+
66
+ /** Maps outputs configuration to inferred output types with status wrapper */
67
+ export type InferOutputsFromConfigs<
68
+ Args,
69
+ OutputsCfg extends Record<string, TypedConfigOrConfigLambda>,
70
+ UiState,
71
+ > = {
72
+ [Key in keyof OutputsCfg]:
73
+ & OutputWithStatus<InferOutputType<OutputsCfg[Key], Args, UiState>>
74
+ & { __unwrap: (OutputsCfg[Key] extends { withStatus: true } ? false : true) };
75
+ };
76
+
77
+ /** Maps lambda-only outputs configuration to inferred output types (for V3 blocks) */
78
+ export type InferOutputsFromLambdas<
79
+ OutputsCfg extends Record<string, ConfigRenderLambda>,
80
+ > = {
81
+ [Key in keyof OutputsCfg]:
82
+ & OutputWithStatus<ExtractFunctionHandleReturn<OutputsCfg[Key]>>
83
+ & { __unwrap: (OutputsCfg[Key] extends { withStatus: true } ? false : true) };
84
+ };
package/src/bconfig/v3.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { BlockConfigV3Generic } from '@milaboratories/pl-model-common';
1
+ import type { BlockConfigV3Generic, BlockConfigV4Generic } from '@milaboratories/pl-model-common';
2
2
  import type { TypedConfigOrConfigLambda } from './types';
3
3
  import type { ConfigRenderLambda } from './lambdas';
4
4
 
@@ -11,4 +11,14 @@ export type BlockConfigV3<
11
11
  >,
12
12
  > = BlockConfigV3Generic<Args, UiState, TypedConfigOrConfigLambda, ConfigRenderLambda, Outputs>;
13
13
 
14
- export type BlockConfig = BlockConfigV3;
14
+ export type BlockConfigV4<
15
+ Args = unknown,
16
+ Data extends Record<string, unknown> = Record<string, unknown>,
17
+ Outputs extends Record<string, TypedConfigOrConfigLambda> = Record<
18
+ string,
19
+ TypedConfigOrConfigLambda
20
+ >,
21
+ > = BlockConfigV4Generic<Args, Data, TypedConfigOrConfigLambda, ConfigRenderLambda, Outputs>;
22
+
23
+ /** Union of all block config versions with discriminator for type narrowing */
24
+ export type BlockConfig = BlockConfigV3 | BlockConfigV4;
@@ -0,0 +1,49 @@
1
+ import type {
2
+ BlockOutputsBase,
3
+ NavigationState,
4
+ ValueWithUTag,
5
+ ValueWithUTagAndAuthor,
6
+ AuthorMarker,
7
+ ResultOrError,
8
+ BlockStateV3,
9
+ } from '@milaboratories/pl-model-common';
10
+ import type { Operation } from 'fast-json-patch';
11
+ import type { MutateStoragePayload } from './block_storage';
12
+
13
+ /** Defines methods to read and write current block data. */
14
+ export interface BlockApiV3<
15
+ _Args = unknown,
16
+ Outputs extends BlockOutputsBase = BlockOutputsBase,
17
+ _Data = unknown,
18
+ Href extends `/${string}` = `/${string}`,
19
+ > {
20
+ /**
21
+ * Use this method to retrieve block state during UI initialization. Then use
22
+ * {@link onStateUpdates} method to subscribe for updates.
23
+ * */
24
+ loadBlockState(): Promise<ResultOrError<ValueWithUTag<BlockStateV3<Outputs, _Data, Href>>>>;
25
+
26
+ /**
27
+ * Get all json patches (rfc6902) that were applied to the block state.
28
+ * */
29
+ getPatches(uTag: string): Promise<ResultOrError<ValueWithUTagAndAuthor<Operation[]>>>;
30
+
31
+ /**
32
+ * Mutates block storage with the given operation.
33
+ *
34
+ * This method returns when the data is safely saved so in case the window is
35
+ * closed there will be no information losses. This function under the hood
36
+ * may delay actual persistence of the supplied values.
37
+ * */
38
+ mutateStorage(payload: MutateStoragePayload, author?: AuthorMarker): Promise<ResultOrError<void>>;
39
+
40
+ /**
41
+ * Sets block navigation state.
42
+ * */
43
+ setNavigationState(state: NavigationState<Href>): Promise<ResultOrError<void>>;
44
+
45
+ /**
46
+ * Disposes the block API.
47
+ * */
48
+ dispose(): Promise<ResultOrError<void>>;
49
+ }
@@ -0,0 +1,173 @@
1
+ import { tryRegisterCallback } from './internal';
2
+ import { createBlockStorage } from './block_storage';
3
+
4
+ export type MigrationFn<From, To> = (prev: Readonly<From>) => To;
5
+
6
+ /** Versioned data wrapper for persistence */
7
+ export type Versioned<T> = {
8
+ version: number;
9
+ data: T;
10
+ };
11
+
12
+ /** Result of upgrade operation, may include warning if migration failed */
13
+ export type UpgradeResult<T> = Versioned<T> & {
14
+ warning?: string;
15
+ };
16
+
17
+ /** Internal builder for chaining migrations */
18
+ class DataModelBuilder<State> {
19
+ private readonly migrationSteps: Array<(x: unknown) => unknown>;
20
+
21
+ private constructor(steps: Array<(x: unknown) => unknown> = []) {
22
+ this.migrationSteps = steps;
23
+ }
24
+
25
+ /** Start a migration chain from an initial type */
26
+ static from<T = unknown>(): DataModelBuilder<T> {
27
+ return new DataModelBuilder<T>();
28
+ }
29
+
30
+ /** Add a migration step */
31
+ migrate<Next>(fn: MigrationFn<State, Next>): DataModelBuilder<Next> {
32
+ return new DataModelBuilder<Next>([...this.migrationSteps, fn as any]);
33
+ }
34
+
35
+ /** Finalize with initial data, creating the DataModel */
36
+ create<S>(
37
+ initialData: () => S,
38
+ ..._: [State] extends [S] ? [] : [never]
39
+ ): DataModel<S> {
40
+ return DataModel._fromBuilder<S>(this.migrationSteps, initialData);
41
+ }
42
+ }
43
+
44
+ /**
45
+ * DataModel defines the block's data structure, initial values, and migrations.
46
+ * Used by BlockModelV3 to manage data state.
47
+ *
48
+ * @example
49
+ * // Simple data model (no migrations)
50
+ * const dataModel = DataModel.create<BlockData>(() => ({
51
+ * numbers: [],
52
+ * labels: [],
53
+ * }));
54
+ *
55
+ * // Data model with migrations
56
+ * const dataModel = DataModel
57
+ * .from<V1>()
58
+ * .migrate((data) => ({ ...data, labels: [] })) // v1 → v2
59
+ * .migrate((data) => ({ ...data, description: '' })) // v2 → v3
60
+ * .create<BlockData>(() => ({ numbers: [], labels: [], description: '' }));
61
+ */
62
+ export class DataModel<State> {
63
+ private readonly steps: Array<(x: unknown) => unknown>;
64
+ private readonly _initialData: () => State;
65
+
66
+ private constructor(steps: Array<(x: unknown) => unknown>, initialData: () => State) {
67
+ this.steps = steps;
68
+ this._initialData = initialData;
69
+ }
70
+
71
+ /** Start a migration chain from an initial type */
72
+ static from<S>(): DataModelBuilder<S> {
73
+ return DataModelBuilder.from<S>();
74
+ }
75
+
76
+ /** Create a data model with just initial data (no migrations) */
77
+ static create<S>(initialData: () => S): DataModel<S> {
78
+ return new DataModel<S>([], initialData);
79
+ }
80
+
81
+ /** Create from builder (internal use) */
82
+ static _fromBuilder<S>(
83
+ steps: Array<(x: unknown) => unknown>,
84
+ initialData: () => S,
85
+ ): DataModel<S> {
86
+ return new DataModel<S>(steps, initialData);
87
+ }
88
+
89
+ /**
90
+ * Latest version number.
91
+ * Version 1 = initial state, each migration adds 1.
92
+ */
93
+ get version(): number {
94
+ return this.steps.length + 1;
95
+ }
96
+
97
+ /** Number of migration steps */
98
+ get migrationCount(): number {
99
+ return this.steps.length;
100
+ }
101
+
102
+ /** Get initial data */
103
+ initialData(): State {
104
+ return this._initialData();
105
+ }
106
+
107
+ /** Get default data wrapped with current version */
108
+ getDefaultData(): Versioned<State> {
109
+ return { version: this.version, data: this._initialData() };
110
+ }
111
+
112
+ /**
113
+ * Upgrade versioned data from any version to the latest.
114
+ * Applies only the migrations needed (skips already-applied ones).
115
+ * If a migration fails, returns default data with a warning.
116
+ */
117
+ upgrade(versioned: Versioned<unknown>): UpgradeResult<State> {
118
+ const { version: fromVersion, data } = versioned;
119
+
120
+ if (fromVersion > this.version) {
121
+ throw new Error(
122
+ `Cannot downgrade from version ${fromVersion} to ${this.version}`,
123
+ );
124
+ }
125
+
126
+ if (fromVersion === this.version) {
127
+ return { version: this.version, data: data as State };
128
+ }
129
+
130
+ // Apply migrations starting from (fromVersion - 1) index
131
+ // Version 1 -> no migrations applied yet -> start at index 0
132
+ // Version 2 -> migration[0] already applied -> start at index 1
133
+ const startIndex = fromVersion - 1;
134
+ const migrationsToApply = this.steps.slice(startIndex);
135
+
136
+ let currentData: unknown = data;
137
+ for (let i = 0; i < migrationsToApply.length; i++) {
138
+ const stepIndex = startIndex + i;
139
+ const fromVer = stepIndex + 1;
140
+ const toVer = stepIndex + 2;
141
+ try {
142
+ currentData = migrationsToApply[i](currentData);
143
+ } catch (error) {
144
+ const errorMessage = error instanceof Error ? error.message : String(error);
145
+ return {
146
+ ...this.getDefaultData(),
147
+ warning: `Migration v${fromVer}→v${toVer} failed: ${errorMessage}`,
148
+ };
149
+ }
150
+ }
151
+
152
+ return { version: this.version, data: currentData as State };
153
+ }
154
+
155
+ /**
156
+ * Register callbacks for use in the VM.
157
+ * Called by BlockModelV3.create() to set up internal callbacks.
158
+ *
159
+ * All callbacks are prefixed with `__pl_` to indicate internal SDK use:
160
+ * - `__pl_data_initial`: returns initial data for new blocks
161
+ * - `__pl_data_upgrade`: upgrades versioned data from any version to latest
162
+ * - `__pl_storage_initial`: returns initial BlockStorage as JSON string
163
+ */
164
+ registerCallbacks(): void {
165
+ tryRegisterCallback('__pl_data_initial', () => this._initialData());
166
+ tryRegisterCallback('__pl_data_upgrade', (versioned: Versioned<unknown>) => this.upgrade(versioned));
167
+ tryRegisterCallback('__pl_storage_initial', () => {
168
+ const { version, data } = this.getDefaultData();
169
+ const storage = createBlockStorage(data, version);
170
+ return JSON.stringify(storage);
171
+ });
172
+ }
173
+ }