@milaboratories/milaboratories.pool-explorer.model 1.0.113 → 1.0.115

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.
@@ -1,14 +1,14 @@
1
1
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @milaboratories/milaboratories.pool-explorer.model@1.0.113 build /home/runner/_work/platforma/platforma/etc/blocks/pool-explorer/model
3
+ > @milaboratories/milaboratories.pool-explorer.model@1.0.115 build /home/runner/_work/platforma/platforma/etc/blocks/pool-explorer/model
4
4
  > ts-builder build --target block-model && block-tools build-model
5
5
 
6
6
  Building block-model project...
7
7
  ↳ rollup -c /configs/rollup.block-model.config.js
8
8
  
9
9
  ./src/index.ts → dist, dist...
10
- created dist, dist in 10s
10
+ created dist, dist in 2.2s
11
11
  
12
12
  ./src/index.ts → dist...
13
- created dist in 11.3s
13
+ created dist in 3.5s
14
14
  Build completed successfully
@@ -0,0 +1,5 @@
1
+  WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
+
3
+ > @milaboratories/milaboratories.pool-explorer.model@1.0.115 lint /home/runner/_work/platforma/platforma/etc/blocks/pool-explorer/model
4
+ > eslint .
5
+
@@ -1,6 +1,6 @@
1
1
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @milaboratories/milaboratories.pool-explorer.model@1.0.113 type-check /home/runner/_work/platforma/platforma/etc/blocks/pool-explorer/model
3
+ > @milaboratories/milaboratories.pool-explorer.model@1.0.115 type-check /home/runner/_work/platforma/platforma/etc/blocks/pool-explorer/model
4
4
  > ts-builder types --target block-model
5
5
 
6
- ↳ tsc --noEmit --project ./tsconfig.json
6
+ ↳ tsc --noEmit --project ./tsconfig.json --customConditions ,
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @milaboratories/milaboratories.pool-explorer.model
2
2
 
3
+ ## 1.0.115
4
+
5
+ ### Patch Changes
6
+
7
+ - 557172d: Add eslint configuration files and lint scripts to published block model and UI packages
8
+
9
+ ## 1.0.114
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [5deb79a]
14
+ - @platforma-sdk/model@1.47.5
15
+
3
16
  ## 1.0.113
4
17
 
5
18
  ### Patch Changes
package/dist/bundle.js CHANGED
@@ -4538,6 +4538,31 @@
4538
4538
  }
4539
4539
  }
4540
4540
 
4541
+ /**
4542
+ * Just for convenience, usually it is an Error with name 'AbortError'
4543
+ */
4544
+ function stringifyValue(value) {
4545
+ if (typeof value === 'string') {
4546
+ return `String value was thrown: ${value}`;
4547
+ }
4548
+ if (value && typeof value === 'object') {
4549
+ try {
4550
+ return `Plain object was thrown: ${JSON.stringify(value)}`;
4551
+ }
4552
+ catch (jsonError) {
4553
+ const errorMessage = jsonError instanceof Error ? jsonError.message : String(jsonError);
4554
+ return `Non-serializable object was thrown (JSON.stringify failed: ${errorMessage}): ${String(value)}`;
4555
+ }
4556
+ }
4557
+ return String(`Non-Error value (${typeof value}) was thrown: ${value}`);
4558
+ }
4559
+ function ensureError(value) {
4560
+ if (value instanceof Error) {
4561
+ return value;
4562
+ }
4563
+ return new Error(stringifyValue(value));
4564
+ }
4565
+
4541
4566
  function getDefaultExportFromCjs (x) {
4542
4567
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
4543
4568
  }
@@ -4603,6 +4628,30 @@
4603
4628
  function readMetadata(metadata, key) {
4604
4629
  return metadata?.[key];
4605
4630
  }
4631
+ function readMetadataJsonOrThrow(metadata, metadataJson, key, methodNameInError = 'readMetadataJsonOrThrow') {
4632
+ const json = readMetadata(metadata, key);
4633
+ if (json === undefined)
4634
+ return undefined;
4635
+ const schema = metadataJson[key];
4636
+ try {
4637
+ const value = JSON.parse(json);
4638
+ return schema.parse(value);
4639
+ }
4640
+ catch (error) {
4641
+ throw new Error(`${methodNameInError} failed, `
4642
+ + `key: ${String(key)}, `
4643
+ + `value: ${json}, `
4644
+ + `error: ${ensureError(error)}`);
4645
+ }
4646
+ }
4647
+ function readMetadataJson(metadata, metadataJson, key) {
4648
+ try {
4649
+ return readMetadataJsonOrThrow(metadata, metadataJson, key);
4650
+ }
4651
+ catch {
4652
+ return undefined; // treat invalid values as unset
4653
+ }
4654
+ }
4606
4655
  /// Well-known annotations
4607
4656
  const Annotation = {
4608
4657
  DiscreteValues: 'pl7.app/discreteValues',
@@ -4640,7 +4689,7 @@
4640
4689
  Trace: 'pl7.app/trace',
4641
4690
  };
4642
4691
  const ValueTypeSchema = z.enum(['Int', 'Long', 'Float', 'Double', 'String']);
4643
- ({
4692
+ const AnnotationJson = {
4644
4693
  [Annotation.DiscreteValues]: z.array(z.string()).or(z.array(z.number())),
4645
4694
  [Annotation.Graph.Axis.HighCardinality]: z.boolean(),
4646
4695
  [Annotation.Graph.Axis.LowerLimit]: z.number(),
@@ -4667,14 +4716,156 @@
4667
4716
  [Annotation.Sequence.IsAnnotation]: z.boolean(),
4668
4717
  [Annotation.Table.OrderPriority]: z.number(),
4669
4718
  [Annotation.Trace]: z.record(z.string(), z.unknown()),
4670
- });
4719
+ };
4671
4720
  /// Helper function for reading plain annotation values
4672
4721
  function readAnnotation(spec, key) {
4673
4722
  return readMetadata(spec?.annotations, key);
4674
4723
  }
4724
+ /// Helper function for reading json-encoded annotation values, returns undefined on JSON parsing error
4725
+ function readAnnotationJson(spec, key) {
4726
+ return readMetadataJson(spec?.annotations, AnnotationJson, key);
4727
+ }
4728
+ function isLinkerColumn(column) {
4729
+ return !!readAnnotationJson(column, Annotation.IsLinkerColumn);
4730
+ }
4731
+ function makeAxisTree(axis) {
4732
+ return { axis, children: [] };
4733
+ }
4734
+ /** Build tree by axis parents annotations */
4735
+ function getAxesTree(rootAxis) {
4736
+ const root = makeAxisTree(rootAxis);
4737
+ let nodesQ = [root];
4738
+ while (nodesQ.length) {
4739
+ const nextNodes = [];
4740
+ for (const node of nodesQ) {
4741
+ node.children = node.axis.parentAxesSpec.map(makeAxisTree);
4742
+ nextNodes.push(...node.children);
4743
+ }
4744
+ nodesQ = nextNodes;
4745
+ }
4746
+ return root;
4747
+ }
4748
+ /** Get array of axisSpecs from axisTree */
4749
+ function getArrayFromAxisTree(tree) {
4750
+ const res = [tree.axis];
4751
+ let nodesQ = [tree];
4752
+ while (nodesQ.length) {
4753
+ const nextNodes = [];
4754
+ for (const node of nodesQ) {
4755
+ for (const parent of node.children) {
4756
+ res.push(parent.axis);
4757
+ nextNodes.push(parent);
4758
+ }
4759
+ }
4760
+ nodesQ = nextNodes;
4761
+ }
4762
+ return res;
4763
+ }
4764
+ function canonicalizeAxisWithParents(axis) {
4765
+ return canonicalizeJson(getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId));
4766
+ }
4767
+ function normalizingAxesComparator(axis1, axis2) {
4768
+ if (axis1.name !== axis2.name) {
4769
+ return axis1.name < axis2.name ? 1 : -1;
4770
+ }
4771
+ if (axis1.type !== axis2.type) {
4772
+ return axis1.type < axis2.type ? 1 : -1;
4773
+ }
4774
+ const domain1 = canonicalizeJson(axis1.domain ?? {});
4775
+ const domain2 = canonicalizeJson(axis2.domain ?? {});
4776
+ if (domain1 !== domain2) {
4777
+ return domain1 < domain2 ? 1 : -1;
4778
+ }
4779
+ const parents1 = canonicalizeAxisWithParents(axis1);
4780
+ const parents2 = canonicalizeAxisWithParents(axis2);
4781
+ if (parents1 !== parents2) {
4782
+ return parents1 < parents2 ? 1 : -1;
4783
+ }
4784
+ const annotation1 = canonicalizeJson(axis1.annotations ?? {});
4785
+ const annotation2 = canonicalizeJson(axis2.annotations ?? {});
4786
+ if (annotation1 !== annotation2) {
4787
+ return annotation1 < annotation2 ? 1 : -1;
4788
+ }
4789
+ return 0;
4790
+ }
4791
+ function parseParentsFromAnnotations(axis) {
4792
+ const parentsList = readAnnotationJson(axis, Annotation.Parents);
4793
+ if (parentsList === undefined) {
4794
+ return [];
4795
+ }
4796
+ return parentsList;
4797
+ }
4798
+ function sortParentsDeep(axisSpec) {
4799
+ axisSpec.parentAxesSpec.forEach(sortParentsDeep);
4800
+ axisSpec.parentAxesSpec.sort(normalizingAxesComparator);
4801
+ }
4802
+ function hasCycleOfParents(axisSpec) {
4803
+ const root = makeAxisTree(axisSpec);
4804
+ let nodesQ = [root];
4805
+ const ancestors = new Set(canonicalizeJson(getAxisId(axisSpec)));
4806
+ while (nodesQ.length) {
4807
+ const nextNodes = [];
4808
+ const levelIds = new Set();
4809
+ for (const node of nodesQ) {
4810
+ node.children = node.axis.parentAxesSpec.map(makeAxisTree);
4811
+ for (const child of node.children) {
4812
+ const childId = canonicalizeJson(getAxisId(child.axis));
4813
+ if (!levelIds.has(childId)) {
4814
+ nextNodes.push(child);
4815
+ levelIds.add(childId);
4816
+ if (ancestors.has(childId)) {
4817
+ return true;
4818
+ }
4819
+ ancestors.add(childId);
4820
+ }
4821
+ }
4822
+ }
4823
+ nodesQ = nextNodes;
4824
+ }
4825
+ return false;
4826
+ }
4827
+ /** Create list of normalized axisSpec (parents are in array of specs, not indexes) */
4828
+ function getNormalizedAxesList(axes) {
4829
+ if (!axes.length) {
4830
+ return [];
4831
+ }
4832
+ const modifiedAxes = axes.map((axis) => {
4833
+ const { parentAxes: _, ...copiedRest } = axis;
4834
+ return { ...copiedRest, annotations: { ...copiedRest.annotations }, parentAxesSpec: [] };
4835
+ });
4836
+ axes.forEach((axis, idx) => {
4837
+ const modifiedAxis = modifiedAxes[idx];
4838
+ if (axis.parentAxes) { // if we have parents by indexes then take from the list
4839
+ modifiedAxis.parentAxesSpec = axis.parentAxes.map((idx) => modifiedAxes[idx]);
4840
+ }
4841
+ else { // else try to parse from annotation name
4842
+ const parents = parseParentsFromAnnotations(axis).map((name) => modifiedAxes.find((axis) => axis.name === name));
4843
+ modifiedAxis.parentAxesSpec = parents.some((p) => p === undefined) ? [] : parents;
4844
+ delete modifiedAxis.annotations?.[Annotation.Parents];
4845
+ }
4846
+ });
4847
+ if (modifiedAxes.some(hasCycleOfParents)) { // Axes list is broken
4848
+ modifiedAxes.forEach((axis) => {
4849
+ axis.parentAxesSpec = [];
4850
+ });
4851
+ }
4852
+ else {
4853
+ modifiedAxes.forEach((axis) => {
4854
+ sortParentsDeep(axis);
4855
+ });
4856
+ }
4857
+ return modifiedAxes;
4858
+ }
4675
4859
  /// Well-known column names
4676
4860
  const PColumnName = {
4677
4861
  Label: 'pl7.app/label'};
4862
+ /** Get column id and spec from a column */
4863
+ function getColumnIdAndSpec(column) {
4864
+ return {
4865
+ columnId: column.id,
4866
+ spec: column.spec,
4867
+ };
4868
+ }
4678
4869
  /** Extracts axis ids from axis spec */
4679
4870
  function getAxisId(spec) {
4680
4871
  const { type, name, domain } = spec;
@@ -5161,6 +5352,232 @@
5161
5352
  return canonicalize(result);
5162
5353
  }
5163
5354
 
5355
+ class LinkerMap {
5356
+ /** Graph of linkers connected by axes (single or grouped by parents) */
5357
+ data;
5358
+ constructor(linkerMap) {
5359
+ this.data = linkerMap;
5360
+ }
5361
+ get keys() {
5362
+ return this.data.keys();
5363
+ }
5364
+ get keyAxesIds() {
5365
+ return [...this.data.keys()].map(parseJson);
5366
+ }
5367
+ static fromColumns(columns) {
5368
+ const result = new Map();
5369
+ for (const linker of columns.filter((l) => !!readAnnotationJson(l.spec, Annotation.IsLinkerColumn))) {
5370
+ const groups = LinkerMap.getAxesGroups(getNormalizedAxesList(linker.spec.axesSpec)); // split input axes into groups by parent links from annotation
5371
+ if (groups.length !== 2) {
5372
+ continue; // not a valid linker column
5373
+ }
5374
+ const [left, right] = groups;
5375
+ // In case of group:
5376
+ // A - C
5377
+ // \_ B _ D
5378
+ // E/
5379
+ // put 2 variants as keys:
5380
+ // A - C
5381
+ // \_ B _ D
5382
+ // and
5383
+ // E - B - D
5384
+ const leftKeyVariants = LinkerMap.getAxesRoots(left).map((axis) => {
5385
+ const axes = getArrayFromAxisTree(getAxesTree(axis));
5386
+ const key = canonicalizeJson(axes.map(getAxisId));
5387
+ return [key, axes];
5388
+ });
5389
+ const rightKeyVariants = LinkerMap.getAxesRoots(right).map((axis) => {
5390
+ const axes = getArrayFromAxisTree(getAxesTree(axis));
5391
+ const key = canonicalizeJson(axes.map(getAxisId));
5392
+ return [key, axes];
5393
+ });
5394
+ for (const [keyLeft, spec] of leftKeyVariants) {
5395
+ if (!result.has(keyLeft)) {
5396
+ result.set(keyLeft, { keyAxesSpec: spec, linkWith: new Map() });
5397
+ }
5398
+ }
5399
+ for (const [keyRight, spec] of rightKeyVariants) {
5400
+ if (!result.has(keyRight)) {
5401
+ result.set(keyRight, { keyAxesSpec: spec, linkWith: new Map() });
5402
+ }
5403
+ }
5404
+ for (const [keyLeft] of leftKeyVariants) {
5405
+ for (const [keyRight] of rightKeyVariants) {
5406
+ result.get(keyLeft)?.linkWith.set(keyRight, linker);
5407
+ result.get(keyRight)?.linkWith.set(keyLeft, linker);
5408
+ }
5409
+ }
5410
+ }
5411
+ return new this(result);
5412
+ }
5413
+ /** Get all available nodes of linker graphs if start from sourceAxesKeys */
5414
+ searchAvailableAxesKeys(sourceAxesKeys) {
5415
+ const startKeys = new Set(sourceAxesKeys);
5416
+ const allAvailableKeys = new Set();
5417
+ let nextKeys = sourceAxesKeys;
5418
+ while (nextKeys.length) {
5419
+ const next = [];
5420
+ for (const key of nextKeys) {
5421
+ const node = this.data.get(key);
5422
+ if (!node)
5423
+ continue;
5424
+ for (const availableKey of node.linkWith.keys()) {
5425
+ if (!allAvailableKeys.has(availableKey) && !startKeys.has(availableKey)) {
5426
+ next.push(availableKey);
5427
+ allAvailableKeys.add(availableKey);
5428
+ }
5429
+ }
5430
+ }
5431
+ nextKeys = next;
5432
+ }
5433
+ return allAvailableKeys;
5434
+ }
5435
+ /** Get all linker columns that are necessary to reach endKey from startKey */
5436
+ searchLinkerPath(startKey, endKey) {
5437
+ const previous = {};
5438
+ let nextIds = new Set([startKey]);
5439
+ const visited = new Set([startKey]);
5440
+ while (nextIds.size) {
5441
+ const next = new Set();
5442
+ for (const nextId of nextIds) {
5443
+ const node = this.data.get(nextId);
5444
+ if (!node)
5445
+ continue;
5446
+ for (const availableId of node.linkWith.keys()) {
5447
+ previous[availableId] = nextId;
5448
+ if (availableId === endKey) {
5449
+ const ids = [];
5450
+ let current = endKey;
5451
+ while (previous[current] !== startKey) {
5452
+ ids.push(current);
5453
+ current = previous[current];
5454
+ }
5455
+ ids.push(current);
5456
+ return ids.map((id) => this.data.get(id).linkWith.get(previous[id]));
5457
+ }
5458
+ else if (!visited.has(availableId)) {
5459
+ next.add(availableId);
5460
+ visited.add(availableId);
5461
+ }
5462
+ }
5463
+ }
5464
+ nextIds = next;
5465
+ }
5466
+ return [];
5467
+ }
5468
+ getLinkerColumnsForAxes({ from: sourceAxes, to: targetAxes, throwWhenNoLinkExists = true, }) {
5469
+ // start keys - all possible keys in linker map using sourceAxes (for example, all axes of block's columns or all axes of columns in data-inputs)
5470
+ const startKeys = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);
5471
+ return Array.from(new Map(LinkerMap.getAxesRoots(targetAxes)
5472
+ .map(LinkerMap.getLinkerKeyFromAxisSpec) // target keys contain all axes to be linked; if some of target axes has parents they must be in the key
5473
+ .flatMap((targetKey) => {
5474
+ const linkers = startKeys
5475
+ .map((startKey) => this.searchLinkerPath(startKey, targetKey))
5476
+ .reduce((shortestPath, path) => (shortestPath.length && shortestPath.length < path.length) || !path.length ? shortestPath : path, [])
5477
+ .map((linker) => [linker.columnId, linker]);
5478
+ if (!linkers.length && throwWhenNoLinkExists) {
5479
+ throw Error(`Unable to find linker column for ${targetKey}`);
5480
+ }
5481
+ return linkers;
5482
+ })).values());
5483
+ }
5484
+ /** Get list of axisSpecs from keys of linker columns map */
5485
+ getAxesListFromKeysList(keys) {
5486
+ return Array.from(new Map(keys.flatMap((key) => this.data.get(key)?.keyAxesSpec ?? [])
5487
+ .map((axis) => [canonicalizeJson(getAxisId(axis)), axis])).values());
5488
+ }
5489
+ /** Get axes of target axes that are impossible to be linked to source axes with current linker map */
5490
+ getNonLinkableAxes(sourceAxes, targetAxes) {
5491
+ const startKeys = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);
5492
+ // target keys contain all axes to be linked; if some of target axes has parents they must be in the key
5493
+ const targetKeys = targetAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);
5494
+ const axes = Array.from(new Map(targetAxes
5495
+ .filter((_targetAxis, idx) => {
5496
+ const targetKey = targetKeys[idx];
5497
+ return !startKeys.some((startKey) => this.searchLinkerPath(startKey, targetKey).length);
5498
+ })
5499
+ .flatMap((axis) => getArrayFromAxisTree(getAxesTree(axis)).map((axis) => [canonicalizeJson(getAxisId(axis)), axis]))).values());
5500
+ return axes;
5501
+ }
5502
+ /** Get all axes that can be connected to sourceAxes by linkers */
5503
+ getReachableByLinkersAxesFromAxesNormalized(sourceAxes, matchAxisIdFn) {
5504
+ let startKeys = [];
5505
+ if (matchAxisIdFn) {
5506
+ const sourceAxisIdsGrouped = sourceAxes.map((axis) => getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId));
5507
+ for (const sourceAxisIdsGroup of sourceAxisIdsGrouped) {
5508
+ const matched = this.keyAxesIds.find((keyIds) => keyIds.every((linkerKeyAxisId) => sourceAxisIdsGroup.find((sourceAxisId) => matchAxisIdFn(linkerKeyAxisId, sourceAxisId))));
5509
+ if (matched) {
5510
+ startKeys.push(canonicalizeJson(matched));
5511
+ }
5512
+ }
5513
+ }
5514
+ else {
5515
+ startKeys = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);
5516
+ }
5517
+ const availableKeys = this.searchAvailableAxesKeys(startKeys);
5518
+ return this.getAxesListFromKeysList([...availableKeys]);
5519
+ }
5520
+ getReachableByLinkersAxesFromAxes(sourceAxes, matchAxisIdFn) {
5521
+ return this.getReachableByLinkersAxesFromAxesNormalized(getNormalizedAxesList(sourceAxes), matchAxisIdFn);
5522
+ }
5523
+ static getLinkerKeyFromAxisSpec(axis) {
5524
+ return canonicalizeJson(getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId));
5525
+ }
5526
+ /** Split array of axes into several arrays by parents: axes of one group are parents for each other.
5527
+ There are no order inside every group. */
5528
+ static getAxesGroups(axesSpec) {
5529
+ switch (axesSpec.length) {
5530
+ case 0: return [];
5531
+ case 1: return [[axesSpec[0]]];
5532
+ }
5533
+ const axisKeys = axesSpec.map((spec) => canonicalizeJson(getAxisId(spec)));
5534
+ const axisParentsIdxs = axesSpec.map((spec) => new Set(spec.parentAxesSpec
5535
+ .map((spec) => canonicalizeJson(getAxisId(spec)))
5536
+ .map((el) => {
5537
+ const idx = axisKeys.indexOf(el);
5538
+ if (idx === -1) {
5539
+ throw new Error(`malformed axesSpec: ${JSON.stringify(axesSpec)}, unable to locate parent ${el}`);
5540
+ }
5541
+ return idx;
5542
+ })));
5543
+ const allIdxs = [...axesSpec.keys()];
5544
+ const groups = []; // groups of axis indexes
5545
+ const usedIdxs = new Set();
5546
+ let nextFreeEl = allIdxs.find((idx) => !usedIdxs.has(idx));
5547
+ while (nextFreeEl !== undefined) {
5548
+ const currentGroup = [nextFreeEl];
5549
+ usedIdxs.add(nextFreeEl);
5550
+ let nextElsOfCurrentGroup = [nextFreeEl];
5551
+ while (nextElsOfCurrentGroup.length) {
5552
+ const next = new Set();
5553
+ for (const groupIdx of nextElsOfCurrentGroup) {
5554
+ const groupElementParents = axisParentsIdxs[groupIdx];
5555
+ allIdxs.forEach((idx) => {
5556
+ if (idx === groupIdx || usedIdxs.has(idx)) {
5557
+ return;
5558
+ }
5559
+ const parents = axisParentsIdxs[idx];
5560
+ if (parents.has(groupIdx) || groupElementParents.has(idx)) {
5561
+ currentGroup.push(idx);
5562
+ next.add(idx);
5563
+ usedIdxs.add(idx);
5564
+ }
5565
+ });
5566
+ }
5567
+ nextElsOfCurrentGroup = [...next];
5568
+ }
5569
+ groups.push([...currentGroup]);
5570
+ nextFreeEl = allIdxs.find((idx) => !usedIdxs.has(idx));
5571
+ }
5572
+ return groups.map((group) => group.map((idx) => axesSpec[idx]));
5573
+ }
5574
+ /** Get all axes that are not parents of any other axis */
5575
+ static getAxesRoots(axes) {
5576
+ const parentsSet = new Set(axes.flatMap((axis) => axis.parentAxesSpec).map((spec) => canonicalizeJson(getAxisId(spec))));
5577
+ return axes.filter((axis) => !parentsSet.has(canonicalizeJson(getAxisId(axis))));
5578
+ }
5579
+ }
5580
+
5164
5581
  /** Characters in string representation */
5165
5582
  const PlIdLength = 24; // = 15 bytes * 8 bits / 5 bits per char in base32
5166
5583
  z
@@ -6170,7 +6587,7 @@
6170
6587
  return undefined;
6171
6588
  }
6172
6589
  getUniversalEntries(predicateOrSelectors, opts) {
6173
- const { anchorCtx, labelOps: rawLabelOps, dontWaitAllData = false, overrideLabelAnnotation = false, exclude } = opts ?? {};
6590
+ const { anchorCtx, labelOps: rawLabelOps, dontWaitAllData = false, overrideLabelAnnotation = false, exclude, enrichByLinkers = false } = opts ?? {};
6174
6591
  const labelOps = {
6175
6592
  ...(overrideLabelAnnotation && rawLabelOps?.includeNativeLabel !== false ? { includeNativeLabel: true } : {}),
6176
6593
  ...(rawLabelOps ?? {}),
@@ -6343,6 +6760,29 @@
6343
6760
  label: label,
6344
6761
  });
6345
6762
  }
6763
+ const ids = new Set(result.map((entry) => entry.id));
6764
+ if (enrichByLinkers && anchorCtx) {
6765
+ const linkers = result.filter((entry) => isLinkerColumn(entry.spec));
6766
+ if (linkers.length === 0) {
6767
+ return result;
6768
+ }
6769
+ const anchorAxes = Object.values(anchorCtx.anchors).flatMap((anchor) => anchor.axesSpec);
6770
+ const linkerMap = LinkerMap.fromColumns(linkers.map(getColumnIdAndSpec));
6771
+ // loose way of matching
6772
+ function matchAxisIdFn(linkerKeyId, sourceAxisId) {
6773
+ return matchAxisId(linkerKeyId, sourceAxisId) || matchAxisId(sourceAxisId, linkerKeyId);
6774
+ }
6775
+ // search all axes that can be reached by linkers from anchor axes; anchor axes are not in this list;
6776
+ const availableByLinkersAxes = linkerMap.getReachableByLinkersAxesFromAxes(anchorAxes, matchAxisIdFn);
6777
+ // search all columns that includes at least one of additional axes;
6778
+ const availableByLinkersColumns = this.getUniversalEntries((spec) => !isLinkerColumn(spec) && spec.axesSpec.some((columnAxisSpec) => {
6779
+ const columnAxisId = getAxisId(columnAxisSpec);
6780
+ return availableByLinkersAxes.some((axis) => matchAxisIdFn(getAxisId(axis), columnAxisId));
6781
+ }), { anchorCtx, labelOps, dontWaitAllData, overrideLabelAnnotation, exclude });
6782
+ if (availableByLinkersColumns) {
6783
+ result.push(...availableByLinkersColumns.filter((entry) => !ids.has(entry.id)));
6784
+ }
6785
+ }
6346
6786
  return result;
6347
6787
  }
6348
6788
  getColumns(predicateOrSelectors, opts) {
@@ -6918,7 +7358,7 @@
6918
7358
  }
6919
7359
  }
6920
7360
 
6921
- var version = "1.46.0";
7361
+ var version = "1.47.5";
6922
7362
 
6923
7363
  const PlatformaSDKVersion = version;
6924
7364
 
@@ -7170,10 +7610,10 @@
7170
7610
  const platforma = BlockModel.create('Heavy')
7171
7611
  .withArgs({ titleArg: 'The title' })
7172
7612
  .output('allSpecs', (ctx) => ctx.resultPool.getSpecs())
7173
- .sections((ctx) => {
7613
+ .sections((_ctx) => {
7174
7614
  return [{ type: 'link', href: '/', label: 'Main' }];
7175
7615
  })
7176
- .title((ctx) => 'Pool explorer')
7616
+ .title((_ctx) => 'Pool explorer')
7177
7617
  .done();
7178
7618
 
7179
7619
  exports.platforma = platforma;