@milaboratories/milaboratories.ui-examples 1.4.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/block-pack/CHANGELOG.md +6 -0
- package/block-pack/main.plj.gz +0 -0
- package/block-pack/manifest.json +1 -1
- package/block-pack/model.json +1 -1
- package/block-pack/published.json +1 -1
- package/block-pack/ui.tgz +0 -0
- package/dist/AGENTS.d.ts +5763 -1444
- package/dist/AGENTS.d.ts.map +1 -1
- package/dist/index.d.ts +5763 -1444
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3246 -354
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -4453,13 +4453,6 @@ objectType({
|
|
|
4453
4453
|
function assertNever(x) {
|
|
4454
4454
|
throw new Error("Unexpected object: " + x);
|
|
4455
4455
|
}
|
|
4456
|
-
/**
|
|
4457
|
-
* Return unique entries of the array by the provided id
|
|
4458
|
-
* For each id, the last entry is kept
|
|
4459
|
-
*/
|
|
4460
|
-
function uniqueBy(array, makeId) {
|
|
4461
|
-
return [...new Map(array.map((e) => [makeId(e), e])).values()];
|
|
4462
|
-
}
|
|
4463
4456
|
//#endregion
|
|
4464
4457
|
//#region ../../../../lib/model/common/dist/drivers/pframe/data_info.js
|
|
4465
4458
|
/**
|
|
@@ -4934,7 +4927,7 @@ function hasCycleOfParents(axisSpec) {
|
|
|
4934
4927
|
}
|
|
4935
4928
|
/** Create list of normalized axisSpec (parents are in array of specs, not indexes) */
|
|
4936
4929
|
function getNormalizedAxesList(axes) {
|
|
4937
|
-
if (
|
|
4930
|
+
if (axes.length === 0) return [];
|
|
4938
4931
|
const modifiedAxes = axes.map((axis) => {
|
|
4939
4932
|
const { parentAxes: _, ...copiedRest } = axis;
|
|
4940
4933
|
return {
|
|
@@ -5074,20 +5067,23 @@ function traverseQuerySpec(query, visitor) {
|
|
|
5074
5067
|
secondary: query.secondary.map(traverseEntry)
|
|
5075
5068
|
};
|
|
5076
5069
|
break;
|
|
5077
|
-
case "linkerJoin":
|
|
5070
|
+
case "linkerJoin": {
|
|
5071
|
+
const linker = "type" in query.linker ? query.linker : {
|
|
5072
|
+
type: "column",
|
|
5073
|
+
column: query.linker.column
|
|
5074
|
+
};
|
|
5078
5075
|
result = {
|
|
5079
5076
|
...query,
|
|
5080
|
-
linker:
|
|
5081
|
-
...query.linker,
|
|
5082
|
-
column: visitor.column(query.linker.column)
|
|
5083
|
-
},
|
|
5077
|
+
linker: traverseQuerySpec(linker, visitor),
|
|
5084
5078
|
secondary: query.secondary.map(traverseEntry)
|
|
5085
5079
|
};
|
|
5086
5080
|
break;
|
|
5081
|
+
}
|
|
5087
5082
|
case "filter":
|
|
5088
5083
|
case "sort":
|
|
5089
5084
|
case "sliceAxes":
|
|
5090
5085
|
case "transformColumns":
|
|
5086
|
+
case "specOverride":
|
|
5091
5087
|
result = {
|
|
5092
5088
|
...query,
|
|
5093
5089
|
input: traverseQuerySpec(query.input, visitor)
|
|
@@ -5098,8 +5094,8 @@ function traverseQuerySpec(query, visitor) {
|
|
|
5098
5094
|
return visitor.node ? visitor.node(result) : result;
|
|
5099
5095
|
}
|
|
5100
5096
|
/** Recursively maps all column references in a SpecQuery tree. */
|
|
5101
|
-
function mapSpecQueryColumns(query,
|
|
5102
|
-
return traverseQuerySpec(query,
|
|
5097
|
+
function mapSpecQueryColumns(query, visitor) {
|
|
5098
|
+
return traverseQuerySpec(query, visitor);
|
|
5103
5099
|
}
|
|
5104
5100
|
//#endregion
|
|
5105
5101
|
//#region ../../../../lib/model/common/dist/drivers/pframe/table_calculate.js
|
|
@@ -5109,8 +5105,8 @@ function mapPTableDef(def, cb) {
|
|
|
5109
5105
|
src: mapJoinEntry(def.src, cb)
|
|
5110
5106
|
};
|
|
5111
5107
|
}
|
|
5112
|
-
function mapPTableDefV2(def,
|
|
5113
|
-
return { query: mapSpecQueryColumns(def.query,
|
|
5108
|
+
function mapPTableDefV2(def, visitor) {
|
|
5109
|
+
return { query: mapSpecQueryColumns(def.query, visitor) };
|
|
5114
5110
|
}
|
|
5115
5111
|
function mapJoinEntry(entry, cb) {
|
|
5116
5112
|
switch (entry.type) {
|
|
@@ -5159,14 +5155,325 @@ function getPTableColumnId(spec) {
|
|
|
5159
5155
|
}
|
|
5160
5156
|
}
|
|
5161
5157
|
//#endregion
|
|
5158
|
+
//#region ../../../../lib/model/common/dist/drivers/pframe/spec/filtered_column.js
|
|
5159
|
+
function stringifyColumnFilteredId(key) {
|
|
5160
|
+
return canonicalizeJson(createColumnFilteredKey(key));
|
|
5161
|
+
}
|
|
5162
|
+
function isColumnFilteredKey(obj) {
|
|
5163
|
+
return typeof obj === "object" && obj !== null && "__isFiltered" in obj;
|
|
5164
|
+
}
|
|
5165
|
+
function createColumnFilteredKey(props) {
|
|
5166
|
+
const axisFilters = props.axisFilters.toSorted((a, b) => a[0] - b[0]);
|
|
5167
|
+
return {
|
|
5168
|
+
__isFiltered: true,
|
|
5169
|
+
source: props.source,
|
|
5170
|
+
axisFilters
|
|
5171
|
+
};
|
|
5172
|
+
}
|
|
5173
|
+
/**
|
|
5174
|
+
* Drop the axes pinned by `axisFilters` from a {@link PColumnSpec}'s
|
|
5175
|
+
* `axesSpec`. Indices are positional against `spec.axesSpec`. Returns `spec`
|
|
5176
|
+
* unchanged when there are no filters.
|
|
5177
|
+
*
|
|
5178
|
+
* Single source of the Filtered-layer spec math — shared by
|
|
5179
|
+
* `reconstructSpecFromId` (host, id-walking) and `ColumnFilteredRecipe.getSpec`
|
|
5180
|
+
* (sandbox, recipe-graph walking).
|
|
5181
|
+
*/
|
|
5182
|
+
function applyAxisFilters(spec, axisFilters) {
|
|
5183
|
+
if (axisFilters.length === 0) return spec;
|
|
5184
|
+
const fixed = new Set(axisFilters.map(([i]) => i));
|
|
5185
|
+
return {
|
|
5186
|
+
...spec,
|
|
5187
|
+
axesSpec: spec.axesSpec.filter((_, i) => !fixed.has(i))
|
|
5188
|
+
};
|
|
5189
|
+
}
|
|
5190
|
+
//#endregion
|
|
5191
|
+
//#region ../../../../lib/model/common/dist/pool/spec.js
|
|
5192
|
+
function isPObjectId(value) {
|
|
5193
|
+
if (typeof value !== "string") return false;
|
|
5194
|
+
return isPObjectKey(parseJsonSafely(value));
|
|
5195
|
+
}
|
|
5196
|
+
function isPObjectKey(value) {
|
|
5197
|
+
return isLocalPObjectKey(value) || isGlobalPObjectKey(value);
|
|
5198
|
+
}
|
|
5199
|
+
function createPObjectId(obj) {
|
|
5200
|
+
if (isLocalPObjectKey(obj)) return createLocalPObjectId(obj.resolvePath, obj.name);
|
|
5201
|
+
if (isGlobalPObjectKey(obj)) return createGlobalPObjectId(obj.blockId, obj.name);
|
|
5202
|
+
throw new Error(`createPObjectId: unrecognized object key structure: ${JSON.stringify(obj)}`);
|
|
5203
|
+
}
|
|
5204
|
+
function createLocalPObjectId(resolvePath, name) {
|
|
5205
|
+
return canonicalizeJson({
|
|
5206
|
+
resolvePath,
|
|
5207
|
+
name
|
|
5208
|
+
});
|
|
5209
|
+
}
|
|
5210
|
+
function isLocalPObjectKey(value) {
|
|
5211
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5212
|
+
const v = value;
|
|
5213
|
+
return Array.isArray(v.resolvePath) && typeof v.name === "string";
|
|
5214
|
+
}
|
|
5215
|
+
function createGlobalPObjectId(blockId, exportName) {
|
|
5216
|
+
return canonicalizeJson({
|
|
5217
|
+
__isRef: true,
|
|
5218
|
+
blockId,
|
|
5219
|
+
name: exportName
|
|
5220
|
+
});
|
|
5221
|
+
}
|
|
5222
|
+
function isGlobalPObjectKey(value) {
|
|
5223
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5224
|
+
return "__isRef" in value && "blockId" in value && "name" in value;
|
|
5225
|
+
}
|
|
5226
|
+
function isPObject(obj) {
|
|
5227
|
+
return typeof obj === "object" && obj !== null && "id" in obj && "spec" in obj && "data" in obj;
|
|
5228
|
+
}
|
|
5229
|
+
function isPColumn(obj) {
|
|
5230
|
+
return isPObject(obj) && isPColumnSpec(obj.spec);
|
|
5231
|
+
}
|
|
5232
|
+
function isPColumnSpec(spec) {
|
|
5233
|
+
return spec.kind === "PColumn";
|
|
5234
|
+
}
|
|
5235
|
+
function ensurePColumn(obj) {
|
|
5236
|
+
if (!isPColumn(obj)) throw new Error(`not a PColumn (kind = ${obj.spec.kind})`);
|
|
5237
|
+
return obj;
|
|
5238
|
+
}
|
|
5239
|
+
function mapPObjectData(pObj, cb) {
|
|
5240
|
+
return pObj === void 0 ? void 0 : {
|
|
5241
|
+
...pObj,
|
|
5242
|
+
data: cb(pObj.data)
|
|
5243
|
+
};
|
|
5244
|
+
}
|
|
5245
|
+
function extractAllColumns(entry) {
|
|
5246
|
+
const columns = /* @__PURE__ */ new Map();
|
|
5247
|
+
const addAllColumns = (entry) => {
|
|
5248
|
+
switch (entry.type) {
|
|
5249
|
+
case "column":
|
|
5250
|
+
columns.set(entry.column.id, entry.column);
|
|
5251
|
+
return;
|
|
5252
|
+
case "slicedColumn":
|
|
5253
|
+
columns.set(entry.column.id, entry.column);
|
|
5254
|
+
return;
|
|
5255
|
+
case "artificialColumn":
|
|
5256
|
+
columns.set(entry.column.id, entry.column);
|
|
5257
|
+
return;
|
|
5258
|
+
case "inlineColumn": return;
|
|
5259
|
+
case "full":
|
|
5260
|
+
case "inner":
|
|
5261
|
+
for (const e of entry.entries) addAllColumns(e);
|
|
5262
|
+
return;
|
|
5263
|
+
case "outer":
|
|
5264
|
+
addAllColumns(entry.primary);
|
|
5265
|
+
for (const e of entry.secondary) addAllColumns(e);
|
|
5266
|
+
return;
|
|
5267
|
+
default: assertNever(entry);
|
|
5268
|
+
}
|
|
5269
|
+
};
|
|
5270
|
+
addAllColumns(entry);
|
|
5271
|
+
return [...columns.values()];
|
|
5272
|
+
}
|
|
5273
|
+
//#endregion
|
|
5274
|
+
//#region ../../../../lib/util/helpers/dist/utils.js
|
|
5275
|
+
function isNil$1(v) {
|
|
5276
|
+
return v === null || v === void 0;
|
|
5277
|
+
}
|
|
5278
|
+
Array.isArray;
|
|
5279
|
+
//#endregion
|
|
5280
|
+
//#region ../../../../lib/util/helpers/dist/error.js
|
|
5281
|
+
function throwError(v) {
|
|
5282
|
+
if (typeof v === "string") throw new Error(v);
|
|
5283
|
+
else throw v;
|
|
5284
|
+
}
|
|
5285
|
+
//#endregion
|
|
5286
|
+
//#region ../../../../lib/model/common/dist/drivers/pframe/spec/discovered_column.js
|
|
5287
|
+
function isColumnDiscoveredKey(obj) {
|
|
5288
|
+
return typeof obj === "object" && obj !== null && "__isDiscovered" in obj;
|
|
5289
|
+
}
|
|
5290
|
+
function distillColumnDiscoveredKey(props) {
|
|
5291
|
+
return {
|
|
5292
|
+
__isDiscovered: true,
|
|
5293
|
+
column: props.column,
|
|
5294
|
+
path: Array.isArray(props.path) && props.path.length > 0 ? props.path : void 0,
|
|
5295
|
+
columnQualifications: Array.isArray(props.columnQualifications) && props.columnQualifications.length > 0 ? props.columnQualifications : void 0,
|
|
5296
|
+
queriesQualifications: props.queriesQualifications && Object.keys(props.queriesQualifications).length > 0 ? props.queriesQualifications : void 0
|
|
5297
|
+
};
|
|
5298
|
+
}
|
|
5299
|
+
function stringifyColumnDiscoveredId(id) {
|
|
5300
|
+
return canonicalizeJson(distillColumnDiscoveredKey({
|
|
5301
|
+
__isDiscovered: true,
|
|
5302
|
+
...id
|
|
5303
|
+
}));
|
|
5304
|
+
}
|
|
5305
|
+
//#endregion
|
|
5306
|
+
//#region ../../../../node_modules/.pnpm/es-toolkit@1.39.10/node_modules/es-toolkit/dist/function/identity.mjs
|
|
5307
|
+
function identity(x) {
|
|
5308
|
+
return x;
|
|
5309
|
+
}
|
|
5310
|
+
//#endregion
|
|
5311
|
+
//#region ../../../../node_modules/.pnpm/es-toolkit@1.39.10/node_modules/es-toolkit/dist/predicate/isFunction.mjs
|
|
5312
|
+
function isFunction(value) {
|
|
5313
|
+
return typeof value === "function";
|
|
5314
|
+
}
|
|
5315
|
+
//#endregion
|
|
5316
|
+
//#region ../../../../node_modules/.pnpm/es-toolkit@1.39.10/node_modules/es-toolkit/dist/predicate/isNil.mjs
|
|
5317
|
+
function isNil(x) {
|
|
5318
|
+
return x == null;
|
|
5319
|
+
}
|
|
5320
|
+
//#endregion
|
|
5321
|
+
//#region ../../../../node_modules/.pnpm/es-toolkit@1.39.10/node_modules/es-toolkit/dist/predicate/isString.mjs
|
|
5322
|
+
function isString(value) {
|
|
5323
|
+
return typeof value === "string";
|
|
5324
|
+
}
|
|
5325
|
+
//#endregion
|
|
5162
5326
|
//#region ../../../../lib/model/common/dist/drivers/pframe/spec/ids.js
|
|
5163
5327
|
/**
|
|
5164
|
-
* Canonically serializes a
|
|
5165
|
-
* @
|
|
5166
|
-
*
|
|
5328
|
+
* Canonically serializes a column key to a branded string id. Accepts both
|
|
5329
|
+
* the new {@link ColumnUniversalKey} and the deprecated {@link UniversalPColumnId}
|
|
5330
|
+
* (anchored / old filtered object form).
|
|
5167
5331
|
*/
|
|
5168
5332
|
function stringifyColumnId(id) {
|
|
5169
|
-
return (
|
|
5333
|
+
return canonicalizeJson(id);
|
|
5334
|
+
}
|
|
5335
|
+
function parseColumnIdSafely(str, fallback = void 0) {
|
|
5336
|
+
try {
|
|
5337
|
+
return JSON.parse(str);
|
|
5338
|
+
} catch {
|
|
5339
|
+
return fallback;
|
|
5340
|
+
}
|
|
5341
|
+
}
|
|
5342
|
+
/**
|
|
5343
|
+
* Walk a rich column id down to its terminal leaf {@link PObjectId}.
|
|
5344
|
+
*/
|
|
5345
|
+
function extractPObjectId(id) {
|
|
5346
|
+
if (isString(id)) {
|
|
5347
|
+
if (isPObjectId(id)) return id;
|
|
5348
|
+
return extractPObjectId(parseColumnIdSafely(id) ?? throwError(`extractPObjectId: id "${id}" is not a valid canonical column id`));
|
|
5349
|
+
}
|
|
5350
|
+
if (isPObjectKey(id)) return createPObjectId(id);
|
|
5351
|
+
if (isColumnFilteredKey(id)) return extractPObjectId(id.source);
|
|
5352
|
+
if (isColumnOverriddenKey(id)) return extractPObjectId(id.source);
|
|
5353
|
+
if (isColumnDiscoveredKey(id)) return extractPObjectId(id.column);
|
|
5354
|
+
throw new Error(`extractPObjectId: unrecognized column id structure: ${JSON.stringify(id)}`);
|
|
5355
|
+
}
|
|
5356
|
+
//#endregion
|
|
5357
|
+
//#region ../../../../lib/model/common/dist/drivers/pframe/spec/overridden.js
|
|
5358
|
+
function isColumnOverriddenKey(obj) {
|
|
5359
|
+
return typeof obj === "object" && obj !== null && "__isOverridden" in obj;
|
|
5360
|
+
}
|
|
5361
|
+
function distillColumnOverriddenKey(props) {
|
|
5362
|
+
return {
|
|
5363
|
+
__isOverridden: true,
|
|
5364
|
+
source: props.source,
|
|
5365
|
+
specOverrides: props.specOverrides
|
|
5366
|
+
};
|
|
5367
|
+
}
|
|
5368
|
+
function createColumnOverriddenId(props) {
|
|
5369
|
+
return stringifyColumnOverriddenId(createColumnOverriddenKey(props));
|
|
5370
|
+
}
|
|
5371
|
+
function createColumnOverriddenKey(props) {
|
|
5372
|
+
const { source, specOverrides } = props;
|
|
5373
|
+
const unwrapped = unwrapOverrides(source);
|
|
5374
|
+
return {
|
|
5375
|
+
__isOverridden: true,
|
|
5376
|
+
source: unwrapped ? unwrapped.source : source,
|
|
5377
|
+
specOverrides: unwrapped ? mergeSpecOverrides(unwrapped.specOverrides, specOverrides) : specOverrides
|
|
5378
|
+
};
|
|
5379
|
+
}
|
|
5380
|
+
function stringifyColumnOverriddenId(id) {
|
|
5381
|
+
return canonicalizeJson(distillColumnOverriddenKey(id));
|
|
5382
|
+
}
|
|
5383
|
+
/**
|
|
5384
|
+
* Peel one override-wrap layer.
|
|
5385
|
+
*
|
|
5386
|
+
* Invariant: `{source, specOverrides}` can only appear at the top level —
|
|
5387
|
+
* the inner `source` is never itself an override-wrap. Anything else throws.
|
|
5388
|
+
*/
|
|
5389
|
+
function unwrapOverrides(id) {
|
|
5390
|
+
const parsed = parseColumnIdSafely(id);
|
|
5391
|
+
if (parsed === void 0 || !isColumnOverriddenKey(parsed)) return void 0;
|
|
5392
|
+
const inner = parseColumnIdSafely(parsed.source);
|
|
5393
|
+
if (inner !== void 0 && isColumnOverriddenKey(inner)) throw new Error("nested override-wrap detected — invariant broken");
|
|
5394
|
+
return parsed;
|
|
5395
|
+
}
|
|
5396
|
+
/**
|
|
5397
|
+
* Apply `specOverrides` from a rich id (`SUniversalPColumnId`) on top of a
|
|
5398
|
+
* resolved {@link PColumnSpec}. Returns `base` unchanged when the id carries
|
|
5399
|
+
* no overrides.
|
|
5400
|
+
*/
|
|
5401
|
+
function applySpecOverrides(base, idOrOverride) {
|
|
5402
|
+
if (isNil(idOrOverride)) return base;
|
|
5403
|
+
const overrides = isString(idOrOverride) ? unwrapOverrides(idOrOverride)?.specOverrides : idOrOverride;
|
|
5404
|
+
if (isNil(overrides)) return base;
|
|
5405
|
+
const result = { ...base };
|
|
5406
|
+
if (overrides.annotations) result.annotations = mergeRecord(base.annotations, overrides.annotations);
|
|
5407
|
+
if (overrides.domain) result.domain = mergeRecord(base.domain, overrides.domain);
|
|
5408
|
+
if (overrides.contextDomain) result.contextDomain = mergeRecord(base.contextDomain, overrides.contextDomain);
|
|
5409
|
+
if (overrides.axesSpec) result.axesSpec = applyAxesPatches(base.axesSpec, overrides.axesSpec);
|
|
5410
|
+
return result;
|
|
5411
|
+
}
|
|
5412
|
+
/**
|
|
5413
|
+
* Compose two override patches: applying `mergeSpecOverrides(prior, next)` on
|
|
5414
|
+
* top of a base spec produces the same result as applying `prior` then `next`.
|
|
5415
|
+
*/
|
|
5416
|
+
function mergeSpecOverrides(prior, next) {
|
|
5417
|
+
const result = {};
|
|
5418
|
+
const axesSpec = mergeAxesPatches(prior.axesSpec, next.axesSpec);
|
|
5419
|
+
if (axesSpec !== void 0) result.axesSpec = axesSpec;
|
|
5420
|
+
const annotations = mergeRecord(prior.annotations, next.annotations);
|
|
5421
|
+
if (annotations !== void 0) result.annotations = annotations;
|
|
5422
|
+
const domain = mergeRecord(prior.domain, next.domain);
|
|
5423
|
+
if (domain !== void 0) result.domain = domain;
|
|
5424
|
+
const contextDomain = mergeRecord(prior.contextDomain, next.contextDomain);
|
|
5425
|
+
if (contextDomain !== void 0) result.contextDomain = contextDomain;
|
|
5426
|
+
return result;
|
|
5427
|
+
}
|
|
5428
|
+
/**
|
|
5429
|
+
* Apply positional `patches` onto `base.axesSpec`. Patches deep-merge
|
|
5430
|
+
* `annotations` / `domain` / `contextDomain` and shallow-override `name` /
|
|
5431
|
+
* `type` at their slot. Indices `>= base.length` append new axes; intermediate
|
|
5432
|
+
* gaps (if any) are filled with the patch itself, so callers should not leave
|
|
5433
|
+
* holes between base.length and the highest patched index.
|
|
5434
|
+
*/
|
|
5435
|
+
function applyAxesPatches(base, patches) {
|
|
5436
|
+
const result = base.slice();
|
|
5437
|
+
for (const [k, p] of Object.entries(patches)) {
|
|
5438
|
+
const i = Number(k);
|
|
5439
|
+
const existing = result[i];
|
|
5440
|
+
result[i] = existing === void 0 ? p : mergeAxisPatch(existing, p);
|
|
5441
|
+
}
|
|
5442
|
+
return result;
|
|
5443
|
+
}
|
|
5444
|
+
/**
|
|
5445
|
+
* Compose two positional patch maps: `mergeAxesPatches(prior, next)` applied to
|
|
5446
|
+
* a base spec must equal applying `prior` then `next`. Patches sharing an
|
|
5447
|
+
* index deep-merge field-by-field.
|
|
5448
|
+
*/
|
|
5449
|
+
function mergeAxesPatches(prior, next) {
|
|
5450
|
+
if (!prior || Object.keys(prior).length === 0) return next;
|
|
5451
|
+
if (!next || Object.keys(next).length === 0) return prior;
|
|
5452
|
+
const result = { ...prior };
|
|
5453
|
+
for (const [k, p] of Object.entries(next)) {
|
|
5454
|
+
const i = Number(k);
|
|
5455
|
+
const existing = result[i];
|
|
5456
|
+
result[i] = existing === void 0 ? p : mergeAxisPatch(existing, p);
|
|
5457
|
+
}
|
|
5458
|
+
return result;
|
|
5459
|
+
}
|
|
5460
|
+
function mergeAxisPatch(axis, patch) {
|
|
5461
|
+
const result = {
|
|
5462
|
+
...axis,
|
|
5463
|
+
...patch
|
|
5464
|
+
};
|
|
5465
|
+
if (patch.annotations) result.annotations = mergeRecord(axis.annotations, patch.annotations);
|
|
5466
|
+
if (patch.domain) result.domain = mergeRecord(axis.domain, patch.domain);
|
|
5467
|
+
if (patch.contextDomain) result.contextDomain = mergeRecord(axis.contextDomain, patch.contextDomain);
|
|
5468
|
+
return result;
|
|
5469
|
+
}
|
|
5470
|
+
function mergeRecord(a, b) {
|
|
5471
|
+
if (!b) return a;
|
|
5472
|
+
if (!a) return b;
|
|
5473
|
+
return {
|
|
5474
|
+
...a,
|
|
5475
|
+
...b
|
|
5476
|
+
};
|
|
5170
5477
|
}
|
|
5171
5478
|
//#endregion
|
|
5172
5479
|
//#region ../../../../lib/model/common/dist/drivers/pframe/spec/anchored.js
|
|
@@ -5415,52 +5722,6 @@ function isAnchorAxisRef(value) {
|
|
|
5415
5722
|
return typeof value === "object" && "anchor" in value;
|
|
5416
5723
|
}
|
|
5417
5724
|
//#endregion
|
|
5418
|
-
//#region ../../../../lib/model/common/dist/pool/spec.js
|
|
5419
|
-
function isPColumnSpec(spec) {
|
|
5420
|
-
return spec.kind === "PColumn";
|
|
5421
|
-
}
|
|
5422
|
-
function isPColumn(obj) {
|
|
5423
|
-
return isPColumnSpec(obj.spec);
|
|
5424
|
-
}
|
|
5425
|
-
function ensurePColumn(obj) {
|
|
5426
|
-
if (!isPColumn(obj)) throw new Error(`not a PColumn (kind = ${obj.spec.kind})`);
|
|
5427
|
-
return obj;
|
|
5428
|
-
}
|
|
5429
|
-
function mapPObjectData(pObj, cb) {
|
|
5430
|
-
return pObj === void 0 ? void 0 : {
|
|
5431
|
-
...pObj,
|
|
5432
|
-
data: cb(typeof pObj.data === "function" ? pObj.data() : pObj.data)
|
|
5433
|
-
};
|
|
5434
|
-
}
|
|
5435
|
-
function extractAllColumns(entry) {
|
|
5436
|
-
const columns = /* @__PURE__ */ new Map();
|
|
5437
|
-
const addAllColumns = (entry) => {
|
|
5438
|
-
switch (entry.type) {
|
|
5439
|
-
case "column":
|
|
5440
|
-
columns.set(entry.column.id, entry.column);
|
|
5441
|
-
return;
|
|
5442
|
-
case "slicedColumn":
|
|
5443
|
-
columns.set(entry.column.id, entry.column);
|
|
5444
|
-
return;
|
|
5445
|
-
case "artificialColumn":
|
|
5446
|
-
columns.set(entry.column.id, entry.column);
|
|
5447
|
-
return;
|
|
5448
|
-
case "inlineColumn": return;
|
|
5449
|
-
case "full":
|
|
5450
|
-
case "inner":
|
|
5451
|
-
for (const e of entry.entries) addAllColumns(e);
|
|
5452
|
-
return;
|
|
5453
|
-
case "outer":
|
|
5454
|
-
addAllColumns(entry.primary);
|
|
5455
|
-
for (const e of entry.secondary) addAllColumns(e);
|
|
5456
|
-
return;
|
|
5457
|
-
default: assertNever(entry);
|
|
5458
|
-
}
|
|
5459
|
-
};
|
|
5460
|
-
addAllColumns(entry);
|
|
5461
|
-
return [...columns.values()];
|
|
5462
|
-
}
|
|
5463
|
-
//#endregion
|
|
5464
5725
|
//#region ../../../../lib/model/common/dist/drivers/pframe/spec/selectors.js
|
|
5465
5726
|
/**
|
|
5466
5727
|
* Determines if an axis ID matches an axis selector.
|
|
@@ -5554,18 +5815,6 @@ function deriveNativeId(spec) {
|
|
|
5554
5815
|
return (0, import_canonicalize.default)(result);
|
|
5555
5816
|
}
|
|
5556
5817
|
//#endregion
|
|
5557
|
-
//#region ../../../../lib/util/helpers/dist/utils.js
|
|
5558
|
-
function isNil$1(v) {
|
|
5559
|
-
return v === null || v === void 0;
|
|
5560
|
-
}
|
|
5561
|
-
Array.isArray;
|
|
5562
|
-
//#endregion
|
|
5563
|
-
//#region ../../../../lib/util/helpers/dist/error.js
|
|
5564
|
-
function throwError(v) {
|
|
5565
|
-
if (typeof v === "string") throw new Error(v);
|
|
5566
|
-
else throw v;
|
|
5567
|
-
}
|
|
5568
|
-
//#endregion
|
|
5569
5818
|
//#region ../../../../lib/model/common/dist/drivers/pframe/linker_columns.js
|
|
5570
5819
|
var LinkerMap = class LinkerMap {
|
|
5571
5820
|
/** Graph of linkers connected by axes (single or grouped by parents) */
|
|
@@ -5795,6 +6044,50 @@ function mapValueInVOE(voe, cb) {
|
|
|
5795
6044
|
} : voe;
|
|
5796
6045
|
}
|
|
5797
6046
|
//#endregion
|
|
6047
|
+
//#region ../../../../lib/model/common/dist/resource_types.js
|
|
6048
|
+
/** Well-known resource type names used across the platform. */
|
|
6049
|
+
const ResourceTypeName = {
|
|
6050
|
+
StreamManager: "StreamManager",
|
|
6051
|
+
StdMap: "StdMap",
|
|
6052
|
+
StdMapSlash: "std/map",
|
|
6053
|
+
EphStdMap: "EphStdMap",
|
|
6054
|
+
PFrame: "PFrame",
|
|
6055
|
+
ParquetChunk: "ParquetChunk",
|
|
6056
|
+
BContext: "BContext",
|
|
6057
|
+
BlockPackCustom: "BlockPackCustom",
|
|
6058
|
+
BinaryMap: "BinaryMap",
|
|
6059
|
+
BinaryValue: "BinaryValue",
|
|
6060
|
+
BlobMap: "BlobMap",
|
|
6061
|
+
BResolveSingle: "BResolveSingle",
|
|
6062
|
+
BResolveSingleNoResult: "BResolveSingleNoResult",
|
|
6063
|
+
BQueryResult: "BQueryResult",
|
|
6064
|
+
TengoTemplate: "TengoTemplate",
|
|
6065
|
+
TengoLib: "TengoLib",
|
|
6066
|
+
SoftwareInfo: "SoftwareInfo",
|
|
6067
|
+
Dummy: "Dummy",
|
|
6068
|
+
JsonResourceError: "json/resourceError",
|
|
6069
|
+
JsonObject: "json/object",
|
|
6070
|
+
JsonGzObject: "json-gz/object",
|
|
6071
|
+
JsonString: "json/string",
|
|
6072
|
+
JsonArray: "json/array",
|
|
6073
|
+
JsonNumber: "json/number",
|
|
6074
|
+
BContextEnd: "BContextEnd",
|
|
6075
|
+
FrontendFromUrl: "Frontend/FromUrl",
|
|
6076
|
+
FrontendFromFolder: "Frontend/FromFolder",
|
|
6077
|
+
BObjectSpec: "BObjectSpec",
|
|
6078
|
+
Blob: "Blob",
|
|
6079
|
+
Null: "Null",
|
|
6080
|
+
Binary: "binary",
|
|
6081
|
+
LSProvider: "LSProvider",
|
|
6082
|
+
WorkingDirectory: "WorkingDirectory",
|
|
6083
|
+
UserProject: "UserProject",
|
|
6084
|
+
Projects: "Projects",
|
|
6085
|
+
ClientRoot: "ClientRoot",
|
|
6086
|
+
SharingOutbox: "SharingOutbox",
|
|
6087
|
+
SharingState: "SharingState",
|
|
6088
|
+
SharedEnvelope: "SharedEnvelope"
|
|
6089
|
+
};
|
|
6090
|
+
//#endregion
|
|
5798
6091
|
//#region ../../../../lib/model/common/dist/services/service_types.js
|
|
5799
6092
|
const SERVICE_ID_PATTERN = /^[a-zA-Z][a-zA-Z0-9]*$/;
|
|
5800
6093
|
const { service, isNodeService, isWasmService, isMainService, getServiceKind, getServiceModelMethods, getServiceUiMethods } = (() => {
|
|
@@ -5892,6 +6185,28 @@ const Services = {
|
|
|
5892
6185
|
name: "dialog",
|
|
5893
6186
|
modelMethods: [],
|
|
5894
6187
|
uiMethods: ["showSaveDialog"]
|
|
6188
|
+
}),
|
|
6189
|
+
ColumnsCollection: service()({
|
|
6190
|
+
type: "wasm",
|
|
6191
|
+
name: "columnsCollection",
|
|
6192
|
+
modelMethods: [
|
|
6193
|
+
"create",
|
|
6194
|
+
"isEmpty",
|
|
6195
|
+
"isFinal",
|
|
6196
|
+
"getColumns",
|
|
6197
|
+
"addSource",
|
|
6198
|
+
"discover",
|
|
6199
|
+
"filter"
|
|
6200
|
+
],
|
|
6201
|
+
uiMethods: [
|
|
6202
|
+
"create",
|
|
6203
|
+
"isEmpty",
|
|
6204
|
+
"isFinal",
|
|
6205
|
+
"getColumns",
|
|
6206
|
+
"addSource",
|
|
6207
|
+
"discover",
|
|
6208
|
+
"filter"
|
|
6209
|
+
]
|
|
5895
6210
|
})
|
|
5896
6211
|
};
|
|
5897
6212
|
Object.keys(Services).map((key) => `requires${key}`);
|
|
@@ -5915,26 +6230,228 @@ function buildMethodMap(pick) {
|
|
|
5915
6230
|
buildMethodMap(getServiceUiMethods);
|
|
5916
6231
|
buildMethodMap(getServiceModelMethods);
|
|
5917
6232
|
//#endregion
|
|
5918
|
-
//#region ../../../../
|
|
5919
|
-
|
|
5920
|
-
|
|
6233
|
+
//#region ../../../../lib/model/common/dist/columns/accessor_traversal.js
|
|
6234
|
+
/** Resource types that hold column collections — DFS stops here and collects. */
|
|
6235
|
+
const COLLECT_TYPES = [ResourceTypeName.PFrame];
|
|
6236
|
+
/** Resource types DFS descends through when looking for PFrames. */
|
|
6237
|
+
const DESCEND_TYPES = [ResourceTypeName.StdMap, ResourceTypeName.StdMapSlash];
|
|
6238
|
+
/**
|
|
6239
|
+
* Enumerate column names backing a PFrame accessor — derived from
|
|
6240
|
+
* `<name>.spec` field names, without resolving the spec resources.
|
|
6241
|
+
*/
|
|
6242
|
+
function listColumnNames(accessor, prefix = "") {
|
|
6243
|
+
if (accessor.resourceType.name !== ResourceTypeName.PFrame) return [];
|
|
6244
|
+
const out = [];
|
|
6245
|
+
for (const field of accessor.listInputFields()) {
|
|
6246
|
+
if (!field.endsWith(".spec")) continue;
|
|
6247
|
+
const raw = field.slice(0, -5);
|
|
6248
|
+
if (!raw.startsWith(prefix)) continue;
|
|
6249
|
+
out.push(raw.slice(prefix.length));
|
|
6250
|
+
}
|
|
6251
|
+
return out;
|
|
5921
6252
|
}
|
|
5922
6253
|
/**
|
|
5923
|
-
*
|
|
5924
|
-
*
|
|
5925
|
-
*
|
|
5926
|
-
*
|
|
6254
|
+
* DFS over the input-field subtree of `root`. Collects nodes whose resource
|
|
6255
|
+
* type ∈ `collectTypes`. Descends only through `descendTypes`
|
|
6256
|
+
* (default: StdMap / StdMapSlash). Collected nodes are not descended into.
|
|
6257
|
+
*
|
|
6258
|
+
* Threads the field-name path from `rootPath` to each hit, so callers can
|
|
6259
|
+
* build canonical {@link createLocalPObjectId}s without relying on the
|
|
6260
|
+
* accessor itself to remember its path.
|
|
6261
|
+
*
|
|
6262
|
+
* Includes `root` itself in the walk.
|
|
5927
6263
|
*/
|
|
5928
|
-
function
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
6264
|
+
function findDescendantsByType(opts) {
|
|
6265
|
+
const { root, rootPath, collectTypes, descendTypes = DESCEND_TYPES } = opts;
|
|
6266
|
+
const collectSet = new Set(collectTypes);
|
|
6267
|
+
const descendSet = new Set(descendTypes);
|
|
6268
|
+
const result = [];
|
|
6269
|
+
const stack = [{
|
|
6270
|
+
node: root,
|
|
6271
|
+
path: rootPath
|
|
6272
|
+
}];
|
|
6273
|
+
while (stack.length > 0) {
|
|
6274
|
+
const { node, path } = stack.pop();
|
|
6275
|
+
const typeName = node.resourceType.name;
|
|
6276
|
+
if (collectSet.has(typeName)) {
|
|
6277
|
+
result.push({
|
|
6278
|
+
node,
|
|
6279
|
+
path
|
|
6280
|
+
});
|
|
6281
|
+
continue;
|
|
6282
|
+
}
|
|
6283
|
+
if (!descendSet.has(typeName)) continue;
|
|
6284
|
+
const fields = node.listInputFields();
|
|
6285
|
+
for (let i = fields.length - 1; i >= 0; i--) {
|
|
6286
|
+
const child = node.traverse({
|
|
6287
|
+
field: fields[i],
|
|
6288
|
+
assertFieldType: "Input",
|
|
6289
|
+
ignoreError: true
|
|
6290
|
+
});
|
|
6291
|
+
if (child !== void 0) stack.push({
|
|
6292
|
+
node: child,
|
|
6293
|
+
path: [...path, fields[i]]
|
|
6294
|
+
});
|
|
6295
|
+
}
|
|
6296
|
+
}
|
|
6297
|
+
return result;
|
|
5934
6298
|
}
|
|
5935
|
-
/**
|
|
5936
|
-
|
|
5937
|
-
|
|
6299
|
+
/**
|
|
6300
|
+
* Walk an accessor root and return one {@link LeafEntry} per discovered column.
|
|
6301
|
+
* Ids are {@link createLocalPObjectId}-shaped: `{resolvePath, name}`. The
|
|
6302
|
+
* `resolvePath` is derived from `rootPath` extended by the DFS traversal.
|
|
6303
|
+
*/
|
|
6304
|
+
function indexAccessorRoot(root, rootPath) {
|
|
6305
|
+
const result = [];
|
|
6306
|
+
for (const { node, path } of findDescendantsByType({
|
|
6307
|
+
root,
|
|
6308
|
+
rootPath,
|
|
6309
|
+
collectTypes: COLLECT_TYPES,
|
|
6310
|
+
descendTypes: DESCEND_TYPES
|
|
6311
|
+
})) for (const name of listColumnNames(node)) result.push({
|
|
6312
|
+
accessor: node,
|
|
6313
|
+
name,
|
|
6314
|
+
id: createLocalPObjectId([...path], name)
|
|
6315
|
+
});
|
|
6316
|
+
return result;
|
|
6317
|
+
}
|
|
6318
|
+
/**
|
|
6319
|
+
* Walk one upstream-block ctx pair (`prodCtx` then `stagingCtx`) and return one
|
|
6320
|
+
* {@link LeafEntry} per column. First-wins dedup by name (prod precedes staging).
|
|
6321
|
+
* Ids are {@link createGlobalPObjectId}-shaped — `resolvePath` is not involved.
|
|
6322
|
+
*/
|
|
6323
|
+
function indexPoolBlock(block) {
|
|
6324
|
+
const accessors = [];
|
|
6325
|
+
if (block.prodCtx) accessors.push(block.prodCtx);
|
|
6326
|
+
if (block.stagingCtx) accessors.push(block.stagingCtx);
|
|
6327
|
+
const result = [];
|
|
6328
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6329
|
+
for (const accessor of accessors) for (const name of listColumnNames(accessor)) {
|
|
6330
|
+
if (seen.has(name)) continue;
|
|
6331
|
+
seen.add(name);
|
|
6332
|
+
result.push({
|
|
6333
|
+
accessor,
|
|
6334
|
+
name,
|
|
6335
|
+
id: createGlobalPObjectId(block.blockId, name)
|
|
6336
|
+
});
|
|
6337
|
+
}
|
|
6338
|
+
return result;
|
|
6339
|
+
}
|
|
6340
|
+
//#endregion
|
|
6341
|
+
//#region ../../../../lib/model/common/dist/columns/column_registry.js
|
|
6342
|
+
/**
|
|
6343
|
+
* Id-index over a set of {@link ColumnEntriesProvider}s. Sole job:
|
|
6344
|
+
* {@link PObjectId} → {@link LeafEntry}. Generic over the accessor flavour, so
|
|
6345
|
+
* the same class backs both sandbox (`TreeNodeAccessor`) and host
|
|
6346
|
+
* (`PlTreeNodeAccessor`) usage.
|
|
6347
|
+
*
|
|
6348
|
+
* Stateless beyond the provider list — every lookup goes through each
|
|
6349
|
+
* provider's `getPObjectEntries()` (cached inside the provider). Instantiate
|
|
6350
|
+
* directly at the call site that has the providers; there is no ambient
|
|
6351
|
+
* singleton.
|
|
6352
|
+
*/
|
|
6353
|
+
var ColumnRegistry = class {
|
|
6354
|
+
providers;
|
|
6355
|
+
constructor(providers) {
|
|
6356
|
+
this.providers = providers;
|
|
6357
|
+
}
|
|
6358
|
+
/**
|
|
6359
|
+
* Resolve a {@link PObjectId} to its backing {@link LeafEntry}. Returns
|
|
6360
|
+
* `undefined` if the column is not reachable from any provider — caller
|
|
6361
|
+
* decides whether that's `absent` or `resolving` via {@link isFinal}.
|
|
6362
|
+
*/
|
|
6363
|
+
resolve(id) {
|
|
6364
|
+
return this.lookupById(id);
|
|
6365
|
+
}
|
|
6366
|
+
/** Whether every indexed source has finished enumerating its columns. */
|
|
6367
|
+
isFinal() {
|
|
6368
|
+
return this.providers.every((p) => p.isFinal());
|
|
6369
|
+
}
|
|
6370
|
+
lookupById(id) {
|
|
6371
|
+
for (const p of this.providers) {
|
|
6372
|
+
const hit = p.getPObjectEntries().get(id);
|
|
6373
|
+
if (hit !== void 0) return hit;
|
|
6374
|
+
}
|
|
6375
|
+
}
|
|
6376
|
+
};
|
|
6377
|
+
//#endregion
|
|
6378
|
+
//#region ../../../../lib/model/common/dist/columns/providers.js
|
|
6379
|
+
/**
|
|
6380
|
+
* Generic entries provider over a single accessor root. Walks `<root>` once
|
|
6381
|
+
* from the supplied `rootPath`, builds an id → {@link LeafEntry} map and
|
|
6382
|
+
* exposes `isFinal()` via the root's `getInputsLocked()`.
|
|
6383
|
+
*
|
|
6384
|
+
* Used directly on the host side; sandbox extends it with `getColumns()`
|
|
6385
|
+
* returning {@link ColumnLazy}s — see `AccessorColumnsProvider` in
|
|
6386
|
+
* `@platforma-sdk/model`.
|
|
6387
|
+
*/
|
|
6388
|
+
var AccessorEntriesProvider = class {
|
|
6389
|
+
root;
|
|
6390
|
+
entries;
|
|
6391
|
+
constructor(root, rootPath) {
|
|
6392
|
+
this.root = root;
|
|
6393
|
+
const map = /* @__PURE__ */ new Map();
|
|
6394
|
+
for (const entry of indexAccessorRoot(root, rootPath)) if (!map.has(entry.id)) map.set(entry.id, entry);
|
|
6395
|
+
this.entries = map;
|
|
6396
|
+
}
|
|
6397
|
+
getPObjectEntries() {
|
|
6398
|
+
return this.entries;
|
|
6399
|
+
}
|
|
6400
|
+
isFinal() {
|
|
6401
|
+
return this.root.getInputsLocked();
|
|
6402
|
+
}
|
|
6403
|
+
};
|
|
6404
|
+
/**
|
|
6405
|
+
* Generic entries provider over a list of upstream-block ctx pairs.
|
|
6406
|
+
*
|
|
6407
|
+
* Per-block merge: iterate `prod` then `staging`, dedupe by name with
|
|
6408
|
+
* first-wins semantics (prod takes precedence).
|
|
6409
|
+
*
|
|
6410
|
+
* `isFinal()` is the AND of `getInputsLocked()` over every present ctx
|
|
6411
|
+
* accessor and `!prodIncomplete && !stagingIncomplete` over every block.
|
|
6412
|
+
*/
|
|
6413
|
+
var ResultPoolEntriesProvider = class {
|
|
6414
|
+
blocks;
|
|
6415
|
+
cachedEntries;
|
|
6416
|
+
constructor(blocks) {
|
|
6417
|
+
this.blocks = blocks;
|
|
6418
|
+
}
|
|
6419
|
+
getPObjectEntries() {
|
|
6420
|
+
if (this.cachedEntries !== void 0) return this.cachedEntries;
|
|
6421
|
+
const map = /* @__PURE__ */ new Map();
|
|
6422
|
+
for (const block of this.blocks) for (const entry of indexPoolBlock(block)) if (!map.has(entry.id)) map.set(entry.id, entry);
|
|
6423
|
+
return this.cachedEntries = map;
|
|
6424
|
+
}
|
|
6425
|
+
isFinal() {
|
|
6426
|
+
for (const block of this.blocks) {
|
|
6427
|
+
if (block.prodIncomplete || block.stagingIncomplete) return false;
|
|
6428
|
+
if (block.prodCtx && !block.prodCtx.getInputsLocked()) return false;
|
|
6429
|
+
if (block.stagingCtx && !block.stagingCtx.getInputsLocked()) return false;
|
|
6430
|
+
}
|
|
6431
|
+
return true;
|
|
6432
|
+
}
|
|
6433
|
+
};
|
|
6434
|
+
//#endregion
|
|
6435
|
+
//#region ../../../../sdk/model/dist/render/accessor.js
|
|
6436
|
+
function ifDef(value, cb) {
|
|
6437
|
+
return value === void 0 ? void 0 : cb(value);
|
|
6438
|
+
}
|
|
6439
|
+
/**
|
|
6440
|
+
* Decode an error node's content into a display message. The backend serializes
|
|
6441
|
+
* a resource error as `{"message": "..."}` (`ResourceError`); unwrap that to the
|
|
6442
|
+
* human-readable message. Falls back to the raw string when the content is not
|
|
6443
|
+
* that envelope (e.g. plain text, or an unexpected shape).
|
|
6444
|
+
*/
|
|
6445
|
+
function decodeErrorMessage(raw) {
|
|
6446
|
+
try {
|
|
6447
|
+
const parsed = JSON.parse(raw);
|
|
6448
|
+
if (typeof parsed?.message === "string") return parsed.message;
|
|
6449
|
+
} catch {}
|
|
6450
|
+
return raw;
|
|
6451
|
+
}
|
|
6452
|
+
/** Represent resource tree node accessor */
|
|
6453
|
+
var TreeNodeAccessor = class TreeNodeAccessor {
|
|
6454
|
+
handle;
|
|
5938
6455
|
resolvePath;
|
|
5939
6456
|
constructor(handle, resolvePath) {
|
|
5940
6457
|
this.handle = handle;
|
|
@@ -5961,7 +6478,7 @@ var TreeNodeAccessor = class TreeNodeAccessor {
|
|
|
5961
6478
|
}));
|
|
5962
6479
|
return this.resolveWithCommon({}, ...transformedSteps);
|
|
5963
6480
|
}
|
|
5964
|
-
|
|
6481
|
+
traverse(...steps) {
|
|
5965
6482
|
return this.resolveWithCommon({}, ...steps);
|
|
5966
6483
|
}
|
|
5967
6484
|
resolveWithCommon(commonOptions, ...steps) {
|
|
@@ -6007,6 +6524,9 @@ var TreeNodeAccessor = class TreeNodeAccessor {
|
|
|
6007
6524
|
if (content == void 0) throw new Error("Resource has no content.");
|
|
6008
6525
|
return JSON.parse(content);
|
|
6009
6526
|
}
|
|
6527
|
+
hasData() {
|
|
6528
|
+
return getCfgRenderCtx().hasData(this.handle);
|
|
6529
|
+
}
|
|
6010
6530
|
getDataBase64() {
|
|
6011
6531
|
return getCfgRenderCtx().getDataBase64(this.handle);
|
|
6012
6532
|
}
|
|
@@ -6043,9 +6563,16 @@ var TreeNodeAccessor = class TreeNodeAccessor {
|
|
|
6043
6563
|
}
|
|
6044
6564
|
return this.getDataAsJson();
|
|
6045
6565
|
}
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6566
|
+
getFileContentAsBase64(range) {
|
|
6567
|
+
return new FutureRef(getCfgRenderCtx().getBlobContentAsBase64(this.handle, range));
|
|
6568
|
+
}
|
|
6569
|
+
getFileContentAsString(range) {
|
|
6570
|
+
return new FutureRef(getCfgRenderCtx().getBlobContentAsString(this.handle, range));
|
|
6571
|
+
}
|
|
6572
|
+
getFileContentAsJson(range) {
|
|
6573
|
+
return new FutureRef(getCfgRenderCtx().getBlobContentAsString(this.handle, range)).mapDefined((v) => JSON.parse(v));
|
|
6574
|
+
}
|
|
6575
|
+
/** @deprecated */
|
|
6049
6576
|
getPColumns(errorOnUnknownField = false, prefix = "") {
|
|
6050
6577
|
const result = this.parsePObjectCollection(errorOnUnknownField, prefix);
|
|
6051
6578
|
if (result === void 0) return void 0;
|
|
@@ -6054,9 +6581,7 @@ var TreeNodeAccessor = class TreeNodeAccessor {
|
|
|
6054
6581
|
return obj;
|
|
6055
6582
|
});
|
|
6056
6583
|
}
|
|
6057
|
-
/**
|
|
6058
|
-
*
|
|
6059
|
-
*/
|
|
6584
|
+
/** @deprecated */
|
|
6060
6585
|
parsePObjectCollection(errorOnUnknownField = false, prefix = "") {
|
|
6061
6586
|
const pObjects = getCfgRenderCtx().parsePObjectCollection(this.handle, errorOnUnknownField, prefix, ...this.resolvePath);
|
|
6062
6587
|
if (pObjects === void 0) return void 0;
|
|
@@ -6067,15 +6592,6 @@ var TreeNodeAccessor = class TreeNodeAccessor {
|
|
|
6067
6592
|
}
|
|
6068
6593
|
return result;
|
|
6069
6594
|
}
|
|
6070
|
-
getFileContentAsBase64(range) {
|
|
6071
|
-
return new FutureRef(getCfgRenderCtx().getBlobContentAsBase64(this.handle, range));
|
|
6072
|
-
}
|
|
6073
|
-
getFileContentAsString(range) {
|
|
6074
|
-
return new FutureRef(getCfgRenderCtx().getBlobContentAsString(this.handle, range));
|
|
6075
|
-
}
|
|
6076
|
-
getFileContentAsJson(range) {
|
|
6077
|
-
return new FutureRef(getCfgRenderCtx().getBlobContentAsString(this.handle, range)).mapDefined((v) => JSON.parse(v));
|
|
6078
|
-
}
|
|
6079
6595
|
/**
|
|
6080
6596
|
* @deprecated use getFileContentAsBase64
|
|
6081
6597
|
*/
|
|
@@ -6167,8 +6683,8 @@ var TreeNodeAccessor = class TreeNodeAccessor {
|
|
|
6167
6683
|
};
|
|
6168
6684
|
//#endregion
|
|
6169
6685
|
//#region ../../../../sdk/model/dist/render/internal.js
|
|
6170
|
-
const StagingAccessorName = "staging";
|
|
6171
6686
|
const MainAccessorName = "main";
|
|
6687
|
+
const StagingAccessorName = "staging";
|
|
6172
6688
|
//#endregion
|
|
6173
6689
|
//#region ../../../../sdk/model/dist/render/util/axis_filtering.js
|
|
6174
6690
|
function filterDataInfoEntries(dataInfoEntries, axisFilters) {
|
|
@@ -6234,46 +6750,229 @@ function filterDataInfoEntries(dataInfoEntries, axisFilters) {
|
|
|
6234
6750
|
}
|
|
6235
6751
|
}
|
|
6236
6752
|
//#endregion
|
|
6237
|
-
//#region ../../../../
|
|
6238
|
-
|
|
6239
|
-
|
|
6753
|
+
//#region ../../../../sdk/model/dist/labels/linked_column_postfix.js
|
|
6754
|
+
/**
|
|
6755
|
+
* Structural postfix derivation for linked columns (phase 2 of `deriveDistinctLabels`).
|
|
6756
|
+
*
|
|
6757
|
+
* A linked column is
|
|
6758
|
+
* reached by a CHAIN of linkers, and we distinguish two such columns by the same ideology the main
|
|
6759
|
+
* algorithm uses — "find the minimal difference, escalate until unique" — over two dimensions:
|
|
6760
|
+
*
|
|
6761
|
+
* - root: the single source axis of the chain, derived from `linkers[0]` (one of its axesSpec).
|
|
6762
|
+
* This is "the source" — it's what we prefer to show ("difference of sources").
|
|
6763
|
+
* - linkers: the linker chain itself (by `LinkLabel`), a per-step fallback used only where roots
|
|
6764
|
+
* coincide.
|
|
6765
|
+
*
|
|
6766
|
+
* Nothing is stored redundantly: the caller passes the linker path (`linkers`) and the hit spec;
|
|
6767
|
+
* root and every token are computed on the fly. The caller also supplies the `stem` (label+trace+
|
|
6768
|
+
* quals from the existing single-entity machinery); this module only adds the path postfix, and
|
|
6769
|
+
* only where stems collide.
|
|
6770
|
+
*/
|
|
6771
|
+
function defaultLinkerFormatter(parts) {
|
|
6772
|
+
const chain = parts.linkers.map((l) => l.text).join(" > ");
|
|
6773
|
+
const pieces = [parts.root?.text, chain || void 0].filter((p) => !isNil(p));
|
|
6774
|
+
return pieces.length === 0 ? "" : `via ${pieces.join(" ")}`;
|
|
6240
6775
|
}
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6776
|
+
function extractAxisIdentity(axis) {
|
|
6777
|
+
const id = getAxisId(axis);
|
|
6778
|
+
return {
|
|
6779
|
+
label: readAnnotation(axis, Annotation.Label)?.trim() || void 0,
|
|
6780
|
+
name: id.name,
|
|
6781
|
+
domain: id.domain,
|
|
6782
|
+
contextDomain: id.contextDomain
|
|
6783
|
+
};
|
|
6245
6784
|
}
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6785
|
+
/**
|
|
6786
|
+
* A linker is named ONLY by its human label (`LinkLabel`/`Label`) — never by its technical column
|
|
6787
|
+
* name. Returns `undefined` for an unlabeled linker, which callers treat as "not renderable": such a
|
|
6788
|
+
* step is skipped, and disambiguation falls to another step or the root.
|
|
6789
|
+
*/
|
|
6790
|
+
function extractLinkerIdentity(linker) {
|
|
6791
|
+
const label = (readAnnotation(linker, Annotation.LinkLabel) ?? readAnnotation(linker, Annotation.Label))?.trim();
|
|
6792
|
+
return label ? {
|
|
6793
|
+
label,
|
|
6794
|
+
name: label
|
|
6795
|
+
} : void 0;
|
|
6796
|
+
}
|
|
6797
|
+
/** Domain keys where `mine` differs from at least one competitor. */
|
|
6798
|
+
function differingKeys(mine, others) {
|
|
6799
|
+
const my = mine ?? {};
|
|
6800
|
+
const diffKeys = /* @__PURE__ */ new Set();
|
|
6801
|
+
for (const o of others) {
|
|
6802
|
+
const od = o ?? {};
|
|
6803
|
+
for (const k of Object.keys(my)) if (my[k] !== od[k]) diffKeys.add(k);
|
|
6804
|
+
for (const k of Object.keys(od)) if (my[k] !== od[k]) diffKeys.add(k);
|
|
6805
|
+
}
|
|
6806
|
+
return [...diffKeys];
|
|
6807
|
+
}
|
|
6808
|
+
function renderWithDomain(base, keys, domain) {
|
|
6809
|
+
if (keys.length === 0) return base;
|
|
6810
|
+
const d = domain ?? {};
|
|
6811
|
+
return `${base}[${keys.map((k) => `${k}=${d[k] ?? "∅"}`).join(", ")}]`;
|
|
6812
|
+
}
|
|
6813
|
+
/**
|
|
6814
|
+
* Minimal token distinguishing `mine` from `others`: label → name → only the differing domain keys.
|
|
6815
|
+
* Falls back to the bare label/name when indistinguishable at this dimension (another one covers it).
|
|
6816
|
+
*/
|
|
6817
|
+
function deriveToken(mine, others) {
|
|
6818
|
+
const base = mine.label ?? mine.name;
|
|
6819
|
+
if (mine.label !== void 0 && others.every((o) => o.label !== mine.label)) return mine.label;
|
|
6820
|
+
if (others.every((o) => o.name !== mine.name)) return base;
|
|
6821
|
+
const dk = differingKeys(mine.domain, others.map((o) => o.domain));
|
|
6822
|
+
if (dk.length > 0) return renderWithDomain(base, dk, mine.domain);
|
|
6823
|
+
const ck = differingKeys(mine.contextDomain, others.map((o) => o.contextDomain));
|
|
6824
|
+
if (ck.length > 0) return renderWithDomain(base, ck, mine.contextDomain);
|
|
6825
|
+
return base;
|
|
6826
|
+
}
|
|
6827
|
+
/**
|
|
6828
|
+
* The chain's single root: the source-side axis of `linkers[0]`. A linker bridges two axis groups;
|
|
6829
|
+
* the side facing the next hop (`linkers[1]`, or the hit for a single-linker chain) is the target,
|
|
6830
|
+
* the other side is the source → its axis is the root. `undefined` if `linkers[0]` is not a
|
|
6831
|
+
* well-formed two-group linker.
|
|
6832
|
+
*/
|
|
6833
|
+
function extractRoot(hit, linkers) {
|
|
6834
|
+
const first = linkers[0];
|
|
6835
|
+
if (first === void 0) return void 0;
|
|
6836
|
+
const axes = first.axesSpec;
|
|
6837
|
+
if (axes.length !== 2) return void 0;
|
|
6838
|
+
const second = linkers[1] ?? hit;
|
|
6839
|
+
return axes.find((a) => !second.axesSpec.some((b) => b.name === a.name));
|
|
6840
|
+
}
|
|
6841
|
+
const ABSENT = "__ABSENT__";
|
|
6842
|
+
function deriveSlotKey(group, slot, row) {
|
|
6843
|
+
if (slot.kind === "root") {
|
|
6844
|
+
const r = group.roots[row];
|
|
6845
|
+
return r === void 0 ? ABSENT : canonicalizeJson(getAxisId(r));
|
|
6846
|
+
} else {
|
|
6847
|
+
const l = group.entries[row].linkers?.[slot.i];
|
|
6848
|
+
const id = l && extractLinkerIdentity(l);
|
|
6849
|
+
return isNil(id) ? ABSENT : canonicalizeJson(id);
|
|
6850
|
+
}
|
|
6851
|
+
}
|
|
6852
|
+
function deriveSlotToken(group, slot, row) {
|
|
6853
|
+
if (slot.kind === "root") {
|
|
6854
|
+
const r = group.roots[row];
|
|
6855
|
+
if (r === void 0) return void 0;
|
|
6856
|
+
const comp = group.roots.filter((o, j) => j !== row && !isNil(o)).map((o) => extractAxisIdentity(o));
|
|
6857
|
+
return deriveToken(extractAxisIdentity(r), comp);
|
|
6858
|
+
}
|
|
6859
|
+
const l = group.entries[row].linkers?.[slot.i];
|
|
6860
|
+
const id = l && extractLinkerIdentity(l);
|
|
6861
|
+
if (isNil(id)) return void 0;
|
|
6862
|
+
return deriveToken(id, group.entries.filter((_, j) => j !== row).map((e) => e.linkers?.[slot.i]).map((x) => x ? extractLinkerIdentity(x) : void 0).filter((x) => !isNil(x)));
|
|
6863
|
+
}
|
|
6864
|
+
function getDiscriminates(group, slot) {
|
|
6865
|
+
return new Set(group.entries.map((_, r) => deriveSlotKey(group, slot, r))).size > 1;
|
|
6866
|
+
}
|
|
6867
|
+
/** Render one row against a chosen slot set: the distinguishing root + linker pieces, formatted. */
|
|
6868
|
+
function renderRow(group, slots, row) {
|
|
6869
|
+
const rootSpec = group.roots[row];
|
|
6870
|
+
const rootText = slots.some((s) => s.kind === "root") ? deriveSlotToken(group, { kind: "root" }, row) : void 0;
|
|
6871
|
+
const root = rootSpec !== void 0 && rootText !== void 0 ? {
|
|
6872
|
+
spec: rootSpec,
|
|
6873
|
+
text: rootText
|
|
6874
|
+
} : void 0;
|
|
6875
|
+
const linkers = slots.filter((s) => s.kind === "linker").sort((a, b) => a.i - b.i).map((s) => {
|
|
6876
|
+
const spec = group.entries[row].linkers?.[s.i];
|
|
6877
|
+
const text = deriveSlotToken(group, s, row);
|
|
6878
|
+
return spec !== void 0 && text !== void 0 ? {
|
|
6879
|
+
spec,
|
|
6880
|
+
text
|
|
6881
|
+
} : void 0;
|
|
6882
|
+
}).filter((l) => !isNil(l));
|
|
6883
|
+
if (root === void 0 && linkers.length === 0) return "";
|
|
6884
|
+
return group.format({
|
|
6885
|
+
root,
|
|
6886
|
+
linkers
|
|
6887
|
+
}, group.entries[row].hit, group.indices[row]) || "";
|
|
6888
|
+
}
|
|
6889
|
+
function renderAll(group, slots) {
|
|
6890
|
+
return group.entries.map((_, r) => renderRow(group, slots, r));
|
|
6891
|
+
}
|
|
6892
|
+
function allUnique(rendered) {
|
|
6893
|
+
return new Set(rendered).size === rendered.length;
|
|
6894
|
+
}
|
|
6895
|
+
/**
|
|
6896
|
+
* Minimal slot set that makes the group unique. Escalate by priority (root, then linkers by step),
|
|
6897
|
+
* then drop any redundant slot; render every row symmetrically against the result.
|
|
6898
|
+
*
|
|
6899
|
+
* KNOWN LIMITATION (review point): symmetric render can over-decorate a row in a mixed group (e.g.
|
|
6900
|
+
* `via Sample MapperA` where `via Sample` alone is already unique for that row). Per-row trimming is
|
|
6901
|
+
* a generalized `dropRedundantLinkerSuffix`; naive greedy trimming is unstable, so it's deferred.
|
|
6902
|
+
*/
|
|
6903
|
+
function resolveGroup(entries, indices, format) {
|
|
6904
|
+
const group = {
|
|
6905
|
+
entries,
|
|
6906
|
+
roots: entries.map((e) => e.hit && e.linkers?.length ? extractRoot(e.hit, e.linkers) : void 0),
|
|
6907
|
+
indices,
|
|
6908
|
+
format
|
|
6909
|
+
};
|
|
6910
|
+
const maxLen = Math.max(0, ...entries.map((e) => e.linkers?.length ?? 0));
|
|
6911
|
+
const escalated = [{ kind: "root" }, ...Array.from({ length: maxLen }, (_, i) => ({
|
|
6912
|
+
kind: "linker",
|
|
6913
|
+
i
|
|
6914
|
+
}))].reduce((acc, slot) => allUnique(renderAll(group, acc)) || !getDiscriminates(group, slot) ? acc : (acc.push(slot), acc), []);
|
|
6915
|
+
return renderAll(group, escalated.reduce((acc, slot) => {
|
|
6916
|
+
const trial = acc.filter((s) => s !== slot);
|
|
6917
|
+
return allUnique(renderAll(group, trial)) ? trial : acc;
|
|
6918
|
+
}, escalated));
|
|
6919
|
+
}
|
|
6920
|
+
/**
|
|
6921
|
+
* Full label per entry: `stem` plus, where stems collide, a minimal postfix distinguishing the
|
|
6922
|
+
* linked columns by the difference between their sources.
|
|
6923
|
+
*/
|
|
6924
|
+
function derivePostfixes(entries, format = defaultLinkerFormatter) {
|
|
6925
|
+
const postfix = [...entries.reduce((acc, e, idx) => acc.set(e.stem, [...acc.get(e.stem) ?? [], idx]), /* @__PURE__ */ new Map()).values()].reduce((acc, idxs) => {
|
|
6926
|
+
if (idxs.length < 2) return acc;
|
|
6927
|
+
const resolved = resolveGroup(idxs.map((i) => entries[i]), idxs, format);
|
|
6928
|
+
return idxs.reduce((m, i, k) => m.set(i, resolved[k]), acc);
|
|
6929
|
+
}, /* @__PURE__ */ new Map());
|
|
6930
|
+
return entries.map((e, i) => {
|
|
6931
|
+
const p = postfix.get(i);
|
|
6932
|
+
return p ? `${e.stem} ${p}` : e.stem;
|
|
6933
|
+
});
|
|
6250
6934
|
}
|
|
6251
6935
|
//#endregion
|
|
6252
6936
|
//#region ../../../../sdk/model/dist/labels/derive_distinct_labels.js
|
|
6253
6937
|
const DISTANCE_PENALTY = .001;
|
|
6254
6938
|
const LABEL_TYPE = "__LABEL__";
|
|
6255
6939
|
const LABEL_TYPE_FULL = "__LABEL__@1";
|
|
6256
|
-
const LINKER_TYPE = "__LINKER__";
|
|
6257
|
-
const LINKER_TYPE_FULL = "__LINKER__@1";
|
|
6258
6940
|
const HIT_QUAL_TYPE = "__HIT_QUAL__";
|
|
6259
6941
|
const ANCHOR_QUAL_TYPE_PREFIX = "__ANCHOR_QUAL__:";
|
|
6260
6942
|
function isAnchorQualType(t) {
|
|
6261
6943
|
return t.startsWith(ANCHOR_QUAL_TYPE_PREFIX);
|
|
6262
6944
|
}
|
|
6263
6945
|
function isSyntheticType(t) {
|
|
6264
|
-
return t ===
|
|
6946
|
+
return t === HIT_QUAL_TYPE || isAnchorQualType(t);
|
|
6265
6947
|
}
|
|
6948
|
+
/**
|
|
6949
|
+
* Distinct labels for a set of columns. Two phases:
|
|
6950
|
+
* 1. {@link deriveStems} — treats each column as a single entity (native label + trace + hit/anchor
|
|
6951
|
+
* qualifications) and produces the minimal distinguishing "stem".
|
|
6952
|
+
* 2. {@link derivePostfixes} — for columns still colliding on their stem, appends a "via …" postfix
|
|
6953
|
+
* describing the difference between their linker sources (root axis, then linker chain).
|
|
6954
|
+
*/
|
|
6266
6955
|
function deriveDistinctLabels(values, options = {}) {
|
|
6956
|
+
const stems = deriveStems(values, options);
|
|
6957
|
+
return derivePostfixes(values.map((v, i) => {
|
|
6958
|
+
const { spec, linkerPath } = extractEntryParts(v);
|
|
6959
|
+
return {
|
|
6960
|
+
stem: stems[i],
|
|
6961
|
+
hit: spec,
|
|
6962
|
+
linkers: (linkerPath ?? []).map((s) => s.spec)
|
|
6963
|
+
};
|
|
6964
|
+
}), options.formatters?.linker);
|
|
6965
|
+
}
|
|
6966
|
+
/** Phase 1: minimal per-column stem — native label + trace + hit/anchor qualifications, no linkers. */
|
|
6967
|
+
function deriveStems(values, options) {
|
|
6267
6968
|
const forceTraceElements = options.forceTraceElements !== void 0 && options.forceTraceElements.length > 0 ? new Set(options.forceTraceElements) : void 0;
|
|
6268
6969
|
const separator = options.separator ?? " / ";
|
|
6269
6970
|
const records = values.map((v, i) => enrichRecord(v, i, options));
|
|
6270
6971
|
const stats = collectTypeStats(records);
|
|
6271
6972
|
const hasAnySynthetic = records.some((r) => r.fullTrace.some((ft) => isSyntheticType(ft.type)));
|
|
6272
6973
|
const labelForced = (options.includeNativeLabel === true || hasAnySynthetic) && stats.countByType.has(LABEL_TYPE_FULL);
|
|
6273
|
-
const linkerForced = stats.countByType.get(LINKER_TYPE_FULL) === values.length;
|
|
6274
6974
|
const forcedSet = /* @__PURE__ */ new Set();
|
|
6275
6975
|
if (labelForced) forcedSet.add(LABEL_TYPE_FULL);
|
|
6276
|
-
if (linkerForced) forcedSet.add(LINKER_TYPE_FULL);
|
|
6277
6976
|
const { mainTypes, secondaryTypes } = classifyTypes(stats, values.length);
|
|
6278
6977
|
const build = (typeSet, force) => buildLabels(records, typeSet, forceTraceElements, separator, force);
|
|
6279
6978
|
if (mainTypes.length === 0) {
|
|
@@ -6289,7 +6988,7 @@ function deriveDistinctLabels(values, options = {}) {
|
|
|
6289
6988
|
const candidateResult = build(currentSet, false);
|
|
6290
6989
|
if (candidateResult !== void 0 && countUniqueLabels(candidateResult) === values.length) {
|
|
6291
6990
|
const minimized = minimizeTypeSet(currentSet, records, stats, forceTraceElements, forcedSet, separator);
|
|
6292
|
-
return
|
|
6991
|
+
return repairBareByPresence(build(minimized, false) ?? throwError("Failed to derive unique labels"), minimized, records, stats, forcedSet, forceTraceElements, separator);
|
|
6293
6992
|
}
|
|
6294
6993
|
additionalType++;
|
|
6295
6994
|
if (additionalType >= mainTypes.length) {
|
|
@@ -6302,7 +7001,7 @@ function deriveDistinctLabels(values, options = {}) {
|
|
|
6302
7001
|
...mainTypes,
|
|
6303
7002
|
...secondaryTypes
|
|
6304
7003
|
]), records, stats, forceTraceElements, forcedSet, separator);
|
|
6305
|
-
return
|
|
7004
|
+
return repairBareByPresence(build(minimized, true) ?? throwError("Failed to derive unique labels"), minimized, records, stats, forcedSet, forceTraceElements, separator);
|
|
6306
7005
|
}
|
|
6307
7006
|
function extractEntryParts(entry) {
|
|
6308
7007
|
if (!("spec" in entry && typeof entry.spec === "object")) return {
|
|
@@ -6328,13 +7027,6 @@ function formatQualification(q) {
|
|
|
6328
7027
|
function formatQualifications(qs) {
|
|
6329
7028
|
return qs.map(formatQualification).join("; ");
|
|
6330
7029
|
}
|
|
6331
|
-
function computeStepLabel(step, stepIndex, formatters) {
|
|
6332
|
-
const base = (readAnnotation(step.spec, Annotation.LinkLabel) ?? readAnnotation(step.spec, Annotation.Label))?.trim();
|
|
6333
|
-
if (isNil(base) || base.length === 0) return void 0;
|
|
6334
|
-
if (step.qualifications === void 0 || step.qualifications.length === 0) return base;
|
|
6335
|
-
const qualText = isFunction(formatters?.linkerStepQualification) ? formatters.linkerStepQualification(step.qualifications, stepIndex, step.spec) : `[${formatQualifications(step.qualifications)}]`;
|
|
6336
|
-
return isNil(qualText) ? base : `${base} ${qualText}`;
|
|
6337
|
-
}
|
|
6338
7030
|
function buildFullTrace(trace) {
|
|
6339
7031
|
const result = [];
|
|
6340
7032
|
const occurrences = /* @__PURE__ */ new Map();
|
|
@@ -6352,7 +7044,7 @@ function buildFullTrace(trace) {
|
|
|
6352
7044
|
return result;
|
|
6353
7045
|
}
|
|
6354
7046
|
function enrichRecord(value, index, options) {
|
|
6355
|
-
const { spec, extraTrace,
|
|
7047
|
+
const { spec, extraTrace, qualifications } = extractEntryParts(value);
|
|
6356
7048
|
const formatters = options.formatters;
|
|
6357
7049
|
const rawLabel = readAnnotation(spec, Annotation.Label);
|
|
6358
7050
|
const traceStr = readAnnotation(spec, Annotation.Trace);
|
|
@@ -6376,17 +7068,6 @@ function enrichRecord(value, index, options) {
|
|
|
6376
7068
|
else trace.splice(0, 0, labelEntry);
|
|
6377
7069
|
}
|
|
6378
7070
|
}
|
|
6379
|
-
if (linkerPath !== void 0 && linkerPath.length > 0) {
|
|
6380
|
-
const stepLabels = linkerPath.map((step, i) => computeStepLabel(step, i, formatters)).filter((s) => !isNil(s));
|
|
6381
|
-
if (stepLabels.length > 0) {
|
|
6382
|
-
const linkerText = isFunction(formatters?.linker) ? formatters.linker(stepLabels, spec, index) : `via ${stepLabels.join(" > ")}`;
|
|
6383
|
-
if (!isNil(linkerText)) trace.push({
|
|
6384
|
-
type: LINKER_TYPE,
|
|
6385
|
-
label: linkerText,
|
|
6386
|
-
importance: -10
|
|
6387
|
-
});
|
|
6388
|
-
}
|
|
6389
|
-
}
|
|
6390
7071
|
if (qualifications !== void 0 && qualifications.forQueries !== void 0) {
|
|
6391
7072
|
for (const [anchorId, qs] of Object.entries(qualifications.forQueries)) {
|
|
6392
7073
|
if (qs.length === 0) continue;
|
|
@@ -6438,21 +7119,18 @@ function classifyTypes(stats, totalRecords) {
|
|
|
6438
7119
|
function renderRecordLabel(record, includedTypes, forceTraceElements, separator) {
|
|
6439
7120
|
const traceParts = [];
|
|
6440
7121
|
const anchorParts = [];
|
|
6441
|
-
let linkerLabel;
|
|
6442
7122
|
let hitLabel;
|
|
6443
7123
|
for (const ft of record.fullTrace) {
|
|
6444
7124
|
if (!(includedTypes.has(ft.fullType) || forceTraceElements?.has(ft.type))) continue;
|
|
6445
|
-
if (ft.type ===
|
|
6446
|
-
else if (ft.type === HIT_QUAL_TYPE) hitLabel = ft.label;
|
|
7125
|
+
if (ft.type === HIT_QUAL_TYPE) hitLabel = ft.label;
|
|
6447
7126
|
else if (isAnchorQualType(ft.type)) anchorParts.push(ft.label);
|
|
6448
7127
|
else traceParts.push(ft.label);
|
|
6449
7128
|
}
|
|
6450
|
-
if (traceParts.length === 0 && anchorParts.length === 0 &&
|
|
7129
|
+
if (traceParts.length === 0 && anchorParts.length === 0 && hitLabel === void 0) return void 0;
|
|
6451
7130
|
let label = traceParts.join(separator);
|
|
6452
7131
|
const append = (part) => {
|
|
6453
7132
|
label = label.length === 0 ? part : `${label} ${part}`;
|
|
6454
7133
|
};
|
|
6455
|
-
if (linkerLabel !== void 0) append(linkerLabel);
|
|
6456
7134
|
for (const a of anchorParts) append(a);
|
|
6457
7135
|
if (hitLabel !== void 0) append(hitLabel);
|
|
6458
7136
|
return label;
|
|
@@ -6470,32 +7148,6 @@ function buildLabels(records, includedTypes, forceTraceElements, separator, forc
|
|
|
6470
7148
|
}
|
|
6471
7149
|
return result;
|
|
6472
7150
|
}
|
|
6473
|
-
/**
|
|
6474
|
-
* Drop the "via …" linker suffix from records whose label is already unique without it.
|
|
6475
|
-
*
|
|
6476
|
-
* Global minimization may include `LINKER_TYPE_FULL` solely to resolve a collision between a
|
|
6477
|
-
* subset of records — but `buildLabels` then renders the suffix on every record that carries a
|
|
6478
|
-
* linker trace entry, including ones whose stem is already unique. We strip the suffix where it
|
|
6479
|
-
* isn't load-bearing while keeping the symmetric rendering required by `linkerForced` /
|
|
6480
|
-
* `forceTraceElements`.
|
|
6481
|
-
*
|
|
6482
|
-
* Rule: a record's linker suffix is redundant iff its stem (label rendered without LINKER) does
|
|
6483
|
-
* not appear anywhere else in the set.
|
|
6484
|
-
*/
|
|
6485
|
-
function dropRedundantLinkerSuffix(records, globalTypeSet, forceTraceElements, forcedSet, separator, labels) {
|
|
6486
|
-
if (!globalTypeSet.has(LINKER_TYPE_FULL)) return labels;
|
|
6487
|
-
if (forcedSet.has(LINKER_TYPE_FULL) || forceTraceElements?.has(LINKER_TYPE)) return labels;
|
|
6488
|
-
const setWithoutLinker = new Set(globalTypeSet);
|
|
6489
|
-
setWithoutLinker.delete(LINKER_TYPE_FULL);
|
|
6490
|
-
const stems = records.map((r) => renderRecordLabel(r, setWithoutLinker, forceTraceElements, separator));
|
|
6491
|
-
const stemOccurrences = /* @__PURE__ */ new Map();
|
|
6492
|
-
for (const s of stems) if (s !== void 0) stemOccurrences.set(s, (stemOccurrences.get(s) ?? 0) + 1);
|
|
6493
|
-
return labels.map((label, i) => {
|
|
6494
|
-
const stem = stems[i];
|
|
6495
|
-
if (stem === void 0) return label;
|
|
6496
|
-
return stemOccurrences.get(stem) === 1 ? stem : label;
|
|
6497
|
-
});
|
|
6498
|
-
}
|
|
6499
7151
|
function countUniqueLabels(result) {
|
|
6500
7152
|
if (result === void 0) return 0;
|
|
6501
7153
|
return new Set(result).size;
|
|
@@ -6514,6 +7166,60 @@ function minimizeTypeSet(typeSet, records, stats, forceTraceElements, forcedSet,
|
|
|
6514
7166
|
}
|
|
6515
7167
|
return result;
|
|
6516
7168
|
}
|
|
7169
|
+
const ABSENT_VALUE = "\0absent";
|
|
7170
|
+
/** Whether `fullType`'s rendered value differs across the group (absence counts as a value). */
|
|
7171
|
+
function typeDistinguishes(records, group, fullType) {
|
|
7172
|
+
const values = /* @__PURE__ */ new Set();
|
|
7173
|
+
for (const i of group) {
|
|
7174
|
+
const ft = records[i].fullTrace.find((e) => e.fullType === fullType);
|
|
7175
|
+
values.add(ft?.label ?? ABSENT_VALUE);
|
|
7176
|
+
if (values.size > 1) return true;
|
|
7177
|
+
}
|
|
7178
|
+
return false;
|
|
7179
|
+
}
|
|
7180
|
+
/** The highest-importance trace type this row HAS (outside `typeSet`) that sets it apart from its
|
|
7181
|
+
* group peers. `undefined` when the row carries nothing distinguishing of its own. */
|
|
7182
|
+
function bestDistinguishingType(records, group, row, typeSet, forcedSet, forceTraceElements, stats) {
|
|
7183
|
+
return records[row].fullTrace.reduce((best, ft) => {
|
|
7184
|
+
if (typeSet.has(ft.fullType) || forcedSet.has(ft.fullType) || forceTraceElements?.has(ft.type)) return best;
|
|
7185
|
+
if (!typeDistinguishes(records, group, ft.fullType)) return best;
|
|
7186
|
+
const imp = stats.importances.get(ft.fullType) ?? 0;
|
|
7187
|
+
return best === void 0 || imp > best.imp ? {
|
|
7188
|
+
type: ft.fullType,
|
|
7189
|
+
imp
|
|
7190
|
+
} : best;
|
|
7191
|
+
}, void 0)?.type;
|
|
7192
|
+
}
|
|
7193
|
+
/**
|
|
7194
|
+
* Un-bare columns distinguished only "by absence". After minimization a column can end up with a
|
|
7195
|
+
* bare trace zone (only the forced native label) while a peer sharing that same base renders extra
|
|
7196
|
+
* tokens — the column reads as unique purely because it LACKS what the peer has. For each such bare
|
|
7197
|
+
* column this re-renders JUST that column's label with the highest-importance trace type it actually
|
|
7198
|
+
* carries that tells it apart from its peers, so every colliding column is distinguished by a token
|
|
7199
|
+
* it HAS rather than by omission.
|
|
7200
|
+
*
|
|
7201
|
+
* Patches individual labels rather than the shared type set on purpose: the set is global, so adding
|
|
7202
|
+
* a type there would also decorate unrelated columns in other groups that happen to carry it. Only
|
|
7203
|
+
* bare columns' labels grow (a superset of their previous value), so uniqueness is preserved. Groups
|
|
7204
|
+
* are keyed by the base = the label rendered from the forced types alone.
|
|
7205
|
+
*/
|
|
7206
|
+
function repairBareByPresence(labels, minimized, records, stats, forcedSet, forceTraceElements, separator) {
|
|
7207
|
+
const base = records.map((r) => renderRecordLabel(r, forcedSet, forceTraceElements, separator));
|
|
7208
|
+
const isBare = records.map((r, i) => renderRecordLabel(r, minimized, forceTraceElements, separator) === base[i]);
|
|
7209
|
+
const groups = records.reduce((acc, _, i) => acc.set(base[i] ?? "", [...acc.get(base[i] ?? "") ?? [], i]), /* @__PURE__ */ new Map());
|
|
7210
|
+
const patched = [...labels];
|
|
7211
|
+
for (const group of groups.values()) {
|
|
7212
|
+
if (!group.some((i) => !isBare[i])) continue;
|
|
7213
|
+
for (const i of group) {
|
|
7214
|
+
if (!isBare[i]) continue;
|
|
7215
|
+
const chosen = bestDistinguishingType(records, group, i, minimized, forcedSet, forceTraceElements, stats);
|
|
7216
|
+
if (chosen === void 0) continue;
|
|
7217
|
+
const withToken = /* @__PURE__ */ new Set([...minimized, chosen]);
|
|
7218
|
+
patched[i] = renderRecordLabel(records[i], withToken, forceTraceElements, separator) ?? patched[i];
|
|
7219
|
+
}
|
|
7220
|
+
}
|
|
7221
|
+
return patched;
|
|
7222
|
+
}
|
|
6517
7223
|
//#endregion
|
|
6518
7224
|
//#region ../../../../sdk/model/dist/render/util/label.js
|
|
6519
7225
|
/** @deprecated Use deriveDistinctLabels */
|
|
@@ -6811,7 +7517,7 @@ function isPColumnReady(c) {
|
|
|
6811
7517
|
const isValues = (d) => Array.isArray(d);
|
|
6812
7518
|
const isAccessor = (d) => d instanceof TreeNodeAccessor;
|
|
6813
7519
|
let ready = true;
|
|
6814
|
-
const data =
|
|
7520
|
+
const data = c.data;
|
|
6815
7521
|
if (data == null) return false;
|
|
6816
7522
|
else if (isAccessor(data)) ready &&= data.getIsReadyOrError();
|
|
6817
7523
|
else if (isDataInfo(data)) visitDataInfo(data, (v) => ready &&= v.getIsReadyOrError());
|
|
@@ -6832,7 +7538,7 @@ function isPColumnValues(value) {
|
|
|
6832
7538
|
/**
|
|
6833
7539
|
* A simple implementation of {@link ColumnProvider} backed by a pre-defined array of columns.
|
|
6834
7540
|
*/
|
|
6835
|
-
var
|
|
7541
|
+
var ArrayColumnsProvider = class {
|
|
6836
7542
|
columns;
|
|
6837
7543
|
constructor(columns) {
|
|
6838
7544
|
this.columns = columns;
|
|
@@ -6884,7 +7590,7 @@ function getSplitAxisIndices(selector) {
|
|
|
6884
7590
|
}
|
|
6885
7591
|
var PColumnCollection = class {
|
|
6886
7592
|
defaultProviderStore = [];
|
|
6887
|
-
providers = [new
|
|
7593
|
+
providers = [new ArrayColumnsProvider(this.defaultProviderStore)];
|
|
6888
7594
|
axisLabelProviders = [];
|
|
6889
7595
|
constructor() {}
|
|
6890
7596
|
addColumnProvider(provider) {
|
|
@@ -7047,7 +7753,9 @@ var PColumnCollection = class {
|
|
|
7047
7753
|
result.push({
|
|
7048
7754
|
id: finalId,
|
|
7049
7755
|
spec: finalSpec,
|
|
7050
|
-
data
|
|
7756
|
+
get data() {
|
|
7757
|
+
return entry.type === "split" ? entriesToDataInfo(filterDataInfoEntries(entry.dataEntries, axisFiltersTuple)) : entry.originalColumn.data;
|
|
7758
|
+
},
|
|
7051
7759
|
label
|
|
7052
7760
|
});
|
|
7053
7761
|
}
|
|
@@ -7083,7 +7791,7 @@ var PColumnCollection = class {
|
|
|
7083
7791
|
if (!entries) return void 0;
|
|
7084
7792
|
const columns = [];
|
|
7085
7793
|
for (const entry of entries) {
|
|
7086
|
-
const data = entry.data
|
|
7794
|
+
const data = entry.data;
|
|
7087
7795
|
if (!data) {
|
|
7088
7796
|
if (opts?.dontWaitAllData) continue;
|
|
7089
7797
|
return;
|
|
@@ -7109,7 +7817,8 @@ var PColumnCollection = class {
|
|
|
7109
7817
|
const BLOCK_SERVICE_FLAGS = {
|
|
7110
7818
|
requiresPFrameSpec: true,
|
|
7111
7819
|
requiresPFrame: true,
|
|
7112
|
-
requiresDialog: true
|
|
7820
|
+
requiresDialog: true,
|
|
7821
|
+
requiresColumnsCollection: true
|
|
7113
7822
|
};
|
|
7114
7823
|
resolveRequiredServices(BLOCK_SERVICE_FLAGS);
|
|
7115
7824
|
//#endregion
|
|
@@ -7124,8 +7833,8 @@ function createServiceProxy(dispatch) {
|
|
|
7124
7833
|
//#endregion
|
|
7125
7834
|
//#region ../../../../sdk/model/dist/services/get_services.js
|
|
7126
7835
|
const cachedServices = /* @__PURE__ */ new WeakMap();
|
|
7127
|
-
function getService(name) {
|
|
7128
|
-
const ctx = getCfgRenderCtx();
|
|
7836
|
+
function getService(name, deps) {
|
|
7837
|
+
const ctx = deps?.ctx ?? getCfgRenderCtx();
|
|
7129
7838
|
const map = cachedServices.has(ctx) ? cachedServices.get(ctx) : (() => {
|
|
7130
7839
|
cachedServices.set(ctx, /* @__PURE__ */ new Map());
|
|
7131
7840
|
return cachedServices.get(ctx);
|
|
@@ -7189,24 +7898,35 @@ function matchDomain(query, target) {
|
|
|
7189
7898
|
}
|
|
7190
7899
|
/**
|
|
7191
7900
|
* Transforms PColumn data into the internal representation expected by the platform
|
|
7192
|
-
* @param
|
|
7901
|
+
* @param column Data from a PColumn to transform
|
|
7193
7902
|
* @returns Transformed data compatible with platform API
|
|
7194
7903
|
*/
|
|
7195
|
-
function
|
|
7196
|
-
return mapPObjectData(
|
|
7197
|
-
if (
|
|
7198
|
-
else if (isDataInfo(
|
|
7199
|
-
|
|
7904
|
+
function finalizePColumnData(column) {
|
|
7905
|
+
return mapPObjectData(column, (data) => {
|
|
7906
|
+
if (data instanceof TreeNodeAccessor) return data.handle;
|
|
7907
|
+
else if (isDataInfo(data)) {
|
|
7908
|
+
let ready = true;
|
|
7909
|
+
visitDataInfo(data, (accessor) => ready &&= accessor?.getIsReadyOrError() ?? false);
|
|
7910
|
+
if (!ready) return [];
|
|
7911
|
+
return mapDataInfo(data, (accessor) => accessor?.handle ?? throwError("Accessor handle is undefined"));
|
|
7912
|
+
} else return data ?? [];
|
|
7200
7913
|
});
|
|
7201
7914
|
}
|
|
7915
|
+
/**
|
|
7916
|
+
* @deprecated use the direct `ctx.*` methods on `RenderCtxBase` instead.
|
|
7917
|
+
*
|
|
7918
|
+
* Migration map:
|
|
7919
|
+
* - `getSpecs` → `ctx.getSpecs`
|
|
7920
|
+
* - `getSpecByRef` / `getPColumnSpecByRef` → `ctx.getSpecByRef` / `ctx.getPColumnSpecByRef`
|
|
7921
|
+
* - `getDataByRef` / `getPColumnByRef` → `ctx.getDataByRef` / `ctx.getPColumnByRef`
|
|
7922
|
+
* - `getOptions` → `ctx.getOptions`
|
|
7923
|
+
*
|
|
7924
|
+
* Eager methods `selectColumns` / `getData` / `getDataWithErrors` should be
|
|
7925
|
+
* replaced by `ctx.getSpecs` + on-demand `ctx.getStatusByRef` /
|
|
7926
|
+
* `ctx.getPColumnByRef` so that the data resource is not subscribed up-front.
|
|
7927
|
+
*/
|
|
7202
7928
|
var ResultPool = class {
|
|
7203
7929
|
ctx = getCfgRenderCtx();
|
|
7204
|
-
/**
|
|
7205
|
-
* @deprecated use getOptions()
|
|
7206
|
-
*/
|
|
7207
|
-
calculateOptions(predicate) {
|
|
7208
|
-
return this.ctx.calculateOptions(predicate);
|
|
7209
|
-
}
|
|
7210
7930
|
getOptions(predicateOrSelector, opts) {
|
|
7211
7931
|
const predicate = typeof predicateOrSelector === "function" ? predicateOrSelector : legacyColumnSelectorsToPredicate(predicateOrSelector);
|
|
7212
7932
|
const filtered = this.getSpecs().entries.filter((s) => predicate(s.obj));
|
|
@@ -7350,7 +8070,6 @@ var ResultPool = class {
|
|
|
7350
8070
|
* @returns data associated with the ref
|
|
7351
8071
|
*/
|
|
7352
8072
|
getDataByRef(ref) {
|
|
7353
|
-
if (typeof this.ctx.getDataFromResultPoolByRef === "undefined") return this.getData().entries.find((f) => f.ref.blockId === ref.blockId && f.ref.name === ref.name)?.obj;
|
|
7354
8073
|
const data = this.ctx.getDataFromResultPoolByRef(ref.blockId, ref.name);
|
|
7355
8074
|
if (!data) return void 0;
|
|
7356
8075
|
return mapPObjectData(data, (handle) => new TreeNodeAccessor(handle, [ref.blockId, ref.name]));
|
|
@@ -7431,6 +8150,9 @@ var ResultPool = class {
|
|
|
7431
8150
|
*
|
|
7432
8151
|
* @param selectors - A predicate function, a single selector, or an array of selectors.
|
|
7433
8152
|
* @returns An array of PColumn objects matching the selectors. Data is loaded on first access.
|
|
8153
|
+
* @deprecated use `RenderCtxBase.rawResultPool` + `ResultPoolColumnsProvider` +
|
|
8154
|
+
* `discoverColumns` instead. This eager path materializes column data
|
|
8155
|
+
* unnecessarily for callers that only filter by spec.
|
|
7434
8156
|
*/
|
|
7435
8157
|
selectColumns(selectors) {
|
|
7436
8158
|
const predicate = typeof selectors === "function" ? selectors : legacyColumnSelectorsToPredicate(selectors);
|
|
@@ -7508,20 +8230,8 @@ var RenderCtxBase = class {
|
|
|
7508
8230
|
get outputs() {
|
|
7509
8231
|
return this.getNamedAccessor(MainAccessorName);
|
|
7510
8232
|
}
|
|
8233
|
+
/** @deprecated use `rawResultPool` + `ResultPoolColumnsProvider` instead. */
|
|
7511
8234
|
resultPool = new ResultPool();
|
|
7512
|
-
/**
|
|
7513
|
-
* Find labels data for a given axis id. It will search for a label column and return its data as a map.
|
|
7514
|
-
* @returns a map of axis value => label
|
|
7515
|
-
* @deprecated Use resultPool.findLabels instead
|
|
7516
|
-
*/
|
|
7517
|
-
findLabels(axis) {
|
|
7518
|
-
return this.resultPool.findLabels(axis);
|
|
7519
|
-
}
|
|
7520
|
-
verifyInlineAndExplicitColumnsSupport(columns) {
|
|
7521
|
-
const hasInlineColumns = columns.some((c) => !(c.data instanceof TreeNodeAccessor) || isDataInfo(c.data));
|
|
7522
|
-
const inlineColumnsSupport = this.ctx.featureFlags?.inlineColumnsSupport === true;
|
|
7523
|
-
if (hasInlineColumns && !inlineColumnsSupport) throw Error(`Inline or explicit columns not supported`);
|
|
7524
|
-
}
|
|
7525
8235
|
patchPTableDef(def) {
|
|
7526
8236
|
if (!this.ctx.featureFlags?.pTablePartitionFiltersSupport) def = {
|
|
7527
8237
|
...def,
|
|
@@ -7536,7 +8246,7 @@ var RenderCtxBase = class {
|
|
|
7536
8246
|
return def;
|
|
7537
8247
|
}
|
|
7538
8248
|
createPFrame(def) {
|
|
7539
|
-
return this.ctx.createPFrame(def.map((
|
|
8249
|
+
return this.ctx.createPFrame(def.map((v) => isString(v) ? v : finalizePColumnData(v)));
|
|
7540
8250
|
}
|
|
7541
8251
|
createPTable(def) {
|
|
7542
8252
|
let rawDef;
|
|
@@ -7553,17 +8263,11 @@ var RenderCtxBase = class {
|
|
|
7553
8263
|
sorting: def.sorting ?? []
|
|
7554
8264
|
});
|
|
7555
8265
|
else rawDef = this.patchPTableDef(def);
|
|
7556
|
-
|
|
7557
|
-
this.
|
|
7558
|
-
if (!allPColumnsReady(columns)) return void 0;
|
|
7559
|
-
return this.ctx.createPTable(mapPTableDef(rawDef, (po) => transformPColumnData(po)));
|
|
8266
|
+
if (!allPColumnsReady(extractAllColumns(rawDef.src))) return void 0;
|
|
8267
|
+
return this.ctx.createPTable(mapPTableDef(rawDef, finalizePColumnData));
|
|
7560
8268
|
}
|
|
7561
8269
|
createPTableV2(def) {
|
|
7562
|
-
return this.ctx.createPTableV2(mapPTableDefV2(def, (
|
|
7563
|
-
}
|
|
7564
|
-
/** @deprecated scheduled for removal from SDK */
|
|
7565
|
-
getBlockLabel(blockId) {
|
|
7566
|
-
return this.ctx.getBlockLabel(blockId);
|
|
8270
|
+
return this.ctx.createPTableV2(mapPTableDefV2(def, { column: (v) => isString(v) ? v : finalizePColumnData(v) }));
|
|
7567
8271
|
}
|
|
7568
8272
|
getCurrentUnstableMarker() {
|
|
7569
8273
|
return this.ctx.getCurrentUnstableMarker();
|
|
@@ -7629,7 +8333,7 @@ var PluginRenderCtx = class extends RenderCtxBase {
|
|
|
7629
8333
|
};
|
|
7630
8334
|
//#endregion
|
|
7631
8335
|
//#region ../../../../sdk/model/dist/version.js
|
|
7632
|
-
const PlatformaSDKVersion = "1.
|
|
8336
|
+
const PlatformaSDKVersion = "1.80.8";
|
|
7633
8337
|
//#endregion
|
|
7634
8338
|
//#region ../../../../sdk/model/dist/bconfig/types.js
|
|
7635
8339
|
function isConfigLambda(cfgOrFh) {
|
|
@@ -8137,79 +8841,2124 @@ var BlockModelV3 = class BlockModelV3 {
|
|
|
8137
8841
|
}
|
|
8138
8842
|
};
|
|
8139
8843
|
//#endregion
|
|
8140
|
-
//#region ../../../../sdk/model/dist/
|
|
8844
|
+
//#region ../../../../sdk/model/dist/columns/column_recipes/leaf_rebrand.js
|
|
8141
8845
|
/**
|
|
8142
|
-
*
|
|
8143
|
-
*
|
|
8144
|
-
*
|
|
8145
|
-
*
|
|
8846
|
+
* Replace every column leaf whose id equals `fromId` with `toId`, leaving
|
|
8847
|
+
* other column refs (linkers, sub-anchors) intact. Wrapper recipes
|
|
8848
|
+
* (Overridden / Filtered) and Discovered use this to lift their own id onto
|
|
8849
|
+
* the hit leaf, so per-variant uniqueness propagates to the engine and
|
|
8850
|
+
* resolver-emitted ids match leaves in the emitted SpecQuery.
|
|
8146
8851
|
*
|
|
8147
|
-
*
|
|
8148
|
-
*
|
|
8149
|
-
*
|
|
8150
|
-
*
|
|
8852
|
+
* Generic over all SpecQuery node shapes — including `linkerJoin`, which
|
|
8853
|
+
* occurs when a wrapper sits over a {@link ColumnDiscoveredRecipe}: only
|
|
8854
|
+
* the deepest hit leaf carries `fromId`, every linker leaf has a different
|
|
8855
|
+
* id and is left untouched.
|
|
8151
8856
|
*/
|
|
8152
|
-
function
|
|
8153
|
-
|
|
8857
|
+
function rebrandLeafId(node, fromId, toId) {
|
|
8858
|
+
if (fromId === toId) return node;
|
|
8859
|
+
return mapSpecQueryColumns(node, { column: (id) => id === fromId ? toId : id });
|
|
8154
8860
|
}
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8861
|
+
//#endregion
|
|
8862
|
+
//#region ../../../../sdk/model/dist/columns/column_recipes/column_overrided_recipe.js
|
|
8863
|
+
/**
|
|
8864
|
+
* Recipe wrapper that overlays {@link SpecOverrides} on top of any other
|
|
8865
|
+
* recipe. The id is `ColumnOverriddenKey { source: inner.id, specOverrides }`.
|
|
8866
|
+
*
|
|
8867
|
+
* Flat-merge invariant: `inner` is never another {@link ColumnOverriddenRecipe}.
|
|
8868
|
+
* Repeated overrides go through {@link wrap} / {@link withSpecs}, which merge
|
|
8869
|
+
* `specOverrides` at the current level and keep wrapper depth constant.
|
|
8870
|
+
*
|
|
8871
|
+
* This invariant matches the one enforced inside `unwrapOverrides` from
|
|
8872
|
+
* pl-model-common: it explicitly throws on a nested override-wrap.
|
|
8873
|
+
*/
|
|
8874
|
+
var ColumnOverriddenRecipe = class ColumnOverriddenRecipe {
|
|
8875
|
+
inner;
|
|
8876
|
+
overrides;
|
|
8877
|
+
/**
|
|
8878
|
+
* Wrap any recipe with overrides. If `inner` is already a
|
|
8879
|
+
* {@link ColumnOverriddenRecipe}, merges `overrides` into the existing ones
|
|
8880
|
+
* and returns a new Overridden sharing the original `inner`. No
|
|
8881
|
+
* `Overridden<Overridden<X>>` is produced.
|
|
8882
|
+
*/
|
|
8883
|
+
static wrap(col, overrides) {
|
|
8884
|
+
if (col instanceof ColumnOverriddenRecipe) return new ColumnOverriddenRecipe(col.inner, mergeSpecOverrides(col.overrides, overrides));
|
|
8885
|
+
return new ColumnOverriddenRecipe(col, overrides);
|
|
8162
8886
|
}
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
|
|
8177
|
-
|
|
8887
|
+
/**
|
|
8888
|
+
* Static counterpart to {@link wrap}: returns the resolution status of a
|
|
8889
|
+
* {@link ColumnOverriddenKey} without constructing the recipe. Overrides
|
|
8890
|
+
* do not add references — status collapses to the source's status.
|
|
8891
|
+
*/
|
|
8892
|
+
static getStatusByKey(key, opts = {}) {
|
|
8893
|
+
return ColumnRecipe.getStatus(key.source, opts);
|
|
8894
|
+
}
|
|
8895
|
+
id;
|
|
8896
|
+
specCache;
|
|
8897
|
+
queryCache;
|
|
8898
|
+
dataStatusCache;
|
|
8899
|
+
constructor(inner, overrides) {
|
|
8900
|
+
this.inner = inner;
|
|
8901
|
+
this.overrides = overrides;
|
|
8902
|
+
this.id = createColumnOverriddenId({
|
|
8903
|
+
source: inner.id,
|
|
8904
|
+
specOverrides: overrides
|
|
8905
|
+
});
|
|
8906
|
+
}
|
|
8907
|
+
/** Wrapped recipe — exposed so external walkers can descend. */
|
|
8908
|
+
getInner() {
|
|
8909
|
+
return this.inner;
|
|
8910
|
+
}
|
|
8911
|
+
/**
|
|
8912
|
+
* `inner` owns all references; overrides are a pure spec patch and do not
|
|
8913
|
+
* introduce new column refs.
|
|
8914
|
+
*/
|
|
8915
|
+
getReferencedIds() {
|
|
8916
|
+
return this.inner.getReferencedIds();
|
|
8917
|
+
}
|
|
8918
|
+
getDataStatus() {
|
|
8919
|
+
if (this.dataStatusCache === void 0) this.dataStatusCache = { value: this.inner.getDataStatus() };
|
|
8920
|
+
return this.dataStatusCache.value;
|
|
8921
|
+
}
|
|
8922
|
+
/**
|
|
8923
|
+
* Take the inner spec and overlay our overrides. `applySpecOverrides`
|
|
8924
|
+
* extracts the overrides from `this.id` itself.
|
|
8925
|
+
*/
|
|
8926
|
+
getSpec() {
|
|
8927
|
+
if (this.specCache === void 0) this.specCache = { value: applySpecOverrides(this.inner.getSpec(), this.id) };
|
|
8928
|
+
return this.specCache.value;
|
|
8929
|
+
}
|
|
8930
|
+
/**
|
|
8931
|
+
* Emit a client-side `specOverride` node wrapping the inner query.
|
|
8932
|
+
*
|
|
8933
|
+
* This is a structural-but-collapsible node: it carries the override
|
|
8934
|
+
* patch through the query tree so consumers see the full recipe shape,
|
|
8935
|
+
* but it is collapsed at the host boundary (`resolvePColumn`) before
|
|
8936
|
+
* the query reaches pframe-engine. The engine never sees this node.
|
|
8937
|
+
*
|
|
8938
|
+
* Overrides do not change query topology — they are a pure spec patch.
|
|
8939
|
+
*/
|
|
8940
|
+
getQuery() {
|
|
8941
|
+
if (this.queryCache === void 0) this.queryCache = { value: {
|
|
8942
|
+
type: "specOverride",
|
|
8943
|
+
input: rebrandLeafId(this.inner.getQuery(), this.inner.id, this.id),
|
|
8944
|
+
override: this.overrides
|
|
8945
|
+
} };
|
|
8946
|
+
return this.queryCache.value;
|
|
8947
|
+
}
|
|
8948
|
+
/**
|
|
8949
|
+
* Flat merge: new overrides merge with existing ones; `inner` is unchanged.
|
|
8950
|
+
* The result is an Overridden of the same depth.
|
|
8951
|
+
*/
|
|
8952
|
+
withSpecs(overrides) {
|
|
8953
|
+
return ColumnOverriddenRecipe.wrap(this, overrides);
|
|
8954
|
+
}
|
|
8955
|
+
};
|
|
8178
8956
|
//#endregion
|
|
8179
|
-
//#region ../../../../sdk/model/dist/
|
|
8180
|
-
/**
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
}
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
}
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8957
|
+
//#region ../../../../sdk/model/dist/columns/column_recipes/column_discovered_recipe.js
|
|
8958
|
+
/**
|
|
8959
|
+
* Recipe for columns identified by a {@link ColumnDiscoveredKey}: a base
|
|
8960
|
+
* column + a `path` of linkers + qualifications.
|
|
8961
|
+
*
|
|
8962
|
+
* Specifics:
|
|
8963
|
+
* - References more than one column (`column` + each `path[i].column`);
|
|
8964
|
+
* {@link getDataStatus} aggregates across the whole set.
|
|
8965
|
+
* - {@link getQuery} assembles the {@link SpecQuery} locally
|
|
8966
|
+
* ({@link buildSpecQuery}) — the hit is inlined as its own recipe's query
|
|
8967
|
+
* tree, linkers fold inside-out into nested `linkerJoin` nodes.
|
|
8968
|
+
* - {@link getSpec} passes through to the hit column's own spec: the linker
|
|
8969
|
+
* chain only enables co-indexing and does not remap the hit's `axesSpec`, so
|
|
8970
|
+
* no engine round-trip is needed (mirrors the Discovered branch of
|
|
8971
|
+
* `reconstructSpecFromId` on the host side).
|
|
8972
|
+
*/
|
|
8973
|
+
var ColumnDiscoveredRecipe = class ColumnDiscoveredRecipe {
|
|
8974
|
+
key;
|
|
8975
|
+
columns;
|
|
8976
|
+
/**
|
|
8977
|
+
* Validate the key + resolve every referenced column via
|
|
8978
|
+
* {@link ColumnLazy.fromId} (which itself checks the leaf accessor reports
|
|
8979
|
+
* `hasData()`). Returns `undefined` if the key is malformed or any
|
|
8980
|
+
* referenced column is not yet spec-resolvable.
|
|
8981
|
+
*
|
|
8982
|
+
* Spec JSON is deserialized lazily on first {@link getSpec}/{@link getQuery}.
|
|
8983
|
+
*/
|
|
8984
|
+
static fromKey(key, opts = {}) {
|
|
8985
|
+
const distilled = distillColumnDiscoveredKey(key);
|
|
8986
|
+
const columns = {};
|
|
8987
|
+
for (const uniId of referencedUniIdsOf(distilled)) {
|
|
8988
|
+
const recipe = Column(uniId, opts);
|
|
8989
|
+
if (recipe === void 0) return void 0;
|
|
8990
|
+
columns[uniId] = recipe;
|
|
8991
|
+
}
|
|
8992
|
+
return new ColumnDiscoveredRecipe(distilled, columns);
|
|
8993
|
+
}
|
|
8994
|
+
/**
|
|
8995
|
+
* Static counterpart to {@link fromKey}: returns the resolution status of
|
|
8996
|
+
* a {@link ColumnDiscoveredKey} without constructing the recipe. Worst-wins
|
|
8997
|
+
* across every referenced {@link ColumnUniversalId} (hit + path linkers),
|
|
8998
|
+
* each resolved via the top-level {@link ColumnRecipe.getStatus} dispatcher.
|
|
8999
|
+
*/
|
|
9000
|
+
static getStatusByKey(key, opts = {}) {
|
|
9001
|
+
const distilled = distillColumnDiscoveredKey(key);
|
|
9002
|
+
let worst = "present";
|
|
9003
|
+
for (const uniId of referencedUniIdsOf(distilled)) {
|
|
9004
|
+
const s = ColumnRecipe.getStatus(uniId, opts);
|
|
9005
|
+
if (s === "absent") return "absent";
|
|
9006
|
+
if (s === "resolving") worst = "resolving";
|
|
9007
|
+
}
|
|
9008
|
+
return worst;
|
|
9009
|
+
}
|
|
9010
|
+
id;
|
|
9011
|
+
specCache;
|
|
9012
|
+
queryCache;
|
|
9013
|
+
dataStatusCache;
|
|
9014
|
+
constructor(key, columns) {
|
|
9015
|
+
this.key = key;
|
|
9016
|
+
this.columns = columns;
|
|
9017
|
+
this.id = stringifyColumnDiscoveredId(this.key);
|
|
9018
|
+
}
|
|
9019
|
+
/**
|
|
9020
|
+
* Universal id of the hit column (excluding path/qualifications on top).
|
|
9021
|
+
* May itself be a wrapped id (Overridden / Filtered / nested Discovered) —
|
|
9022
|
+
* preserves projections applied to the underlying column.
|
|
9023
|
+
*/
|
|
9024
|
+
getHitId() {
|
|
9025
|
+
return this.key.column;
|
|
9026
|
+
}
|
|
9027
|
+
/**
|
|
9028
|
+
* Axis qualifications attached to the hit column itself — applied to the
|
|
9029
|
+
* outer-join entry that wraps this column at the consumer boundary.
|
|
9030
|
+
*/
|
|
9031
|
+
getColumnQualifications() {
|
|
9032
|
+
return this.key.columnQualifications ?? [];
|
|
9033
|
+
}
|
|
9034
|
+
/**
|
|
9035
|
+
* Per-primary-column qualifications applied to the primary anchors on
|
|
9036
|
+
* this group's side. Keyed by the external primary column id.
|
|
9037
|
+
*/
|
|
9038
|
+
getQueriesQualifications() {
|
|
9039
|
+
return this.key.queriesQualifications ?? {};
|
|
9040
|
+
}
|
|
9041
|
+
/**
|
|
9042
|
+
* Leaf {@link PObjectId}s the recipe physically depends on: hit column +
|
|
9043
|
+
* each linker in `path`, with any projection wrappers unwrapped down to
|
|
9044
|
+
* their underlying storage column. Used to track real-data dependencies
|
|
9045
|
+
* (e.g. {@link getDataStatus}), not projected identities.
|
|
9046
|
+
*/
|
|
9047
|
+
getReferencedIds() {
|
|
9048
|
+
return [...new Set([...referencedUniIdsOf(this.key)].map((uniId) => extractPObjectId(uniId)))];
|
|
9049
|
+
}
|
|
9050
|
+
/**
|
|
9051
|
+
* Final spec of a discovered hit is just the hit column's own spec: the
|
|
9052
|
+
* linker chain only enables co-indexing, it does not remap the hit's
|
|
9053
|
+
* `axesSpec`, and axis qualifications live on the outer join entry (see
|
|
9054
|
+
* {@link buildSpecQuery}), not in the spec. So pass through to the hit
|
|
9055
|
+
* recipe's `getSpec()` — no engine round-trip needed. This mirrors the
|
|
9056
|
+
* Discovered branch of `reconstructSpecFromId` on the host side.
|
|
9057
|
+
*/
|
|
9058
|
+
getSpec() {
|
|
9059
|
+
if (this.specCache === void 0) {
|
|
9060
|
+
const hit = this.columns[this.key.column] ?? throwError(`ColumnDiscoveredRecipe.getSpec: missing column ${this.key.column}`);
|
|
9061
|
+
this.specCache = { value: hit.getSpec() };
|
|
9062
|
+
}
|
|
9063
|
+
return this.specCache.value;
|
|
9064
|
+
}
|
|
9065
|
+
/** IR for building the final spec — see {@link buildSpecQuery}. */
|
|
9066
|
+
getQuery() {
|
|
9067
|
+
if (this.queryCache === void 0) this.queryCache = { value: this.buildSpecQuery() };
|
|
9068
|
+
return this.queryCache.value;
|
|
9069
|
+
}
|
|
9070
|
+
getDataStatus() {
|
|
9071
|
+
if (this.dataStatusCache === void 0) this.dataStatusCache = { value: Object.values(this.columns).reduce((worst, lazy) => {
|
|
9072
|
+
const s = lazy.getDataStatus();
|
|
9073
|
+
if (s === "absent" || worst === "absent") return "absent";
|
|
9074
|
+
if (s === "resolving") return "resolving";
|
|
9075
|
+
return worst;
|
|
9076
|
+
}, "present") };
|
|
9077
|
+
return this.dataStatusCache.value;
|
|
9078
|
+
}
|
|
9079
|
+
/**
|
|
9080
|
+
* Discovered + overrides → Overridden<Discovered>. Delegates to the
|
|
9081
|
+
* flat-merge factory of ColumnOverriddenRecipe; subsequent `withSpecs`
|
|
9082
|
+
* calls merge at the Overridden level (one wrapper, no nesting).
|
|
9083
|
+
*/
|
|
9084
|
+
withSpecs(overrides) {
|
|
9085
|
+
return ColumnOverriddenRecipe.wrap(this, overrides);
|
|
9086
|
+
}
|
|
9087
|
+
/**
|
|
9088
|
+
* Assembles the SpecQuery for this discovered hit by folding `key.path`
|
|
9089
|
+
* around the hit column.
|
|
9090
|
+
*
|
|
9091
|
+
* The hit (innermost) is built by inlining `columns[key.column].getQuery()`
|
|
9092
|
+
* — recursing into the hit's own recipe — so wrapping layers on the hit
|
|
9093
|
+
* (Overridden / Filtered / nested Discovered) appear in the produced tree.
|
|
9094
|
+
* The previous `pframeSpec.buildQuery` path was a flat
|
|
9095
|
+
* {@link PObjectId}-only call and could not express that.
|
|
9096
|
+
*
|
|
9097
|
+
* Linkers stay as plain column references on the linker side of
|
|
9098
|
+
* `linkerJoin` (the spec node has no slot for a query-side linker); the
|
|
9099
|
+
* linker's recipe id is used directly. The frame registered in
|
|
9100
|
+
* {@link getSpec} carries each recipe's final spec under that same id, so
|
|
9101
|
+
* the engine resolves linker axes from the post-projection spec.
|
|
9102
|
+
*
|
|
9103
|
+
* Path ordering matches {@link ColumnDiscoveredKey.path}: `path[0]` is
|
|
9104
|
+
* outermost, `path[N-1]` is closest to the hit. We fold from the inside
|
|
9105
|
+
* out — innermost wrap first — so the result lines up with that convention.
|
|
9106
|
+
*
|
|
9107
|
+
* `columnQualifications` / `queriesQualifications` are not emitted here —
|
|
9108
|
+
* qualifications live on a {@link SpecQueryJoinEntry} wrapper (lost on
|
|
9109
|
+
* unwrapping to {@link SpecQuery}). External consumers apply them at the
|
|
9110
|
+
* outer join via {@link getColumnQualifications} / {@link getQueriesQualifications}.
|
|
9111
|
+
*/
|
|
9112
|
+
buildSpecQuery() {
|
|
9113
|
+
const hitRecipe = this.columns[this.key.column] ?? throwError(`ColumnDiscoveredRecipe.buildSpecQuery: missing column ${this.key.column}`);
|
|
9114
|
+
let query = rebrandLeafId(hitRecipe.getQuery(), hitRecipe.id, this.id);
|
|
9115
|
+
const path = this.key.path ?? [];
|
|
9116
|
+
for (let i = path.length - 1; i >= 0; i--) query = {
|
|
9117
|
+
type: "linkerJoin",
|
|
9118
|
+
linker: (this.columns[path[i].column] ?? throwError(`ColumnDiscoveredRecipe.buildSpecQuery: missing linker column ${path[i].column}`)).getQuery(),
|
|
9119
|
+
secondary: [{ entry: query }]
|
|
9120
|
+
};
|
|
9121
|
+
return query;
|
|
9122
|
+
}
|
|
9123
|
+
};
|
|
9124
|
+
function referencedUniIdsOf(key) {
|
|
9125
|
+
return /* @__PURE__ */ new Set([key.column, ...(key.path ?? []).map((item) => item.column)]);
|
|
9126
|
+
}
|
|
9127
|
+
//#endregion
|
|
9128
|
+
//#region ../../../../sdk/model/dist/columns/column_recipes/column_filtered_recipe.js
|
|
9129
|
+
/**
|
|
9130
|
+
* Recipe wrapper that fixes the values of selected axes of an inner recipe
|
|
9131
|
+
* (axis slicing). The id is `FilteredPColumnId { source: inner.id,
|
|
9132
|
+
* axisFilters }`.
|
|
9133
|
+
*
|
|
9134
|
+
* Flat-merge invariant: `inner` is never another {@link ColumnFilteredRecipe}.
|
|
9135
|
+
* Repeated {@link wrap} concatenates `axisFilters` at the current level.
|
|
9136
|
+
*
|
|
9137
|
+
* Layering: `withSpecs` on a Filtered recipe yields
|
|
9138
|
+
* `Overridden<Filtered<inner>>` — Overridden is always the outermost layer.
|
|
9139
|
+
* The reverse layering (`Filtered<Overridden<...>>`) is not reachable via
|
|
9140
|
+
* the public interface.
|
|
9141
|
+
*/
|
|
9142
|
+
var ColumnFilteredRecipe = class ColumnFilteredRecipe {
|
|
9143
|
+
inner;
|
|
9144
|
+
axisFilters;
|
|
9145
|
+
/**
|
|
9146
|
+
* Wrap any recipe with axis filters. If `inner` is already a
|
|
9147
|
+
* {@link ColumnFilteredRecipe}, concatenates `axisFilters` and returns a
|
|
9148
|
+
* new Filtered sharing the original `inner`.
|
|
9149
|
+
*
|
|
9150
|
+
* Validates every axis index against `inner.getSpec().axesSpec` at
|
|
9151
|
+
* construction — throws on an out-of-range index. After {@link wrap}, the
|
|
9152
|
+
* recipe is guaranteed to be spec-complete.
|
|
9153
|
+
*
|
|
9154
|
+
* Order semantics: new filters are appended after existing ones, preserving
|
|
9155
|
+
* their relative order. AND composition is otherwise commutative; order
|
|
9156
|
+
* only affects canonicalize/equality.
|
|
9157
|
+
*/
|
|
9158
|
+
static wrap(col, axisFilters) {
|
|
9159
|
+
const combined = col instanceof ColumnFilteredRecipe ? [...col.axisFilters, ...axisFilters] : axisFilters;
|
|
9160
|
+
const base = col instanceof ColumnFilteredRecipe ? col.inner : col;
|
|
9161
|
+
if (combined.length === 0) throw new Error("ColumnFilteredRecipe.wrap: at least one axis filter must be provided");
|
|
9162
|
+
const innerSpec = base.getSpec();
|
|
9163
|
+
const fixed = /* @__PURE__ */ new Set();
|
|
9164
|
+
for (const [idx] of combined) {
|
|
9165
|
+
if (innerSpec.axesSpec[idx] === void 0) throw new Error(`ColumnFilteredRecipe.wrap: axis index ${idx} out of range (inner has ${innerSpec.axesSpec.length} axes)`);
|
|
9166
|
+
fixed.add(idx);
|
|
9167
|
+
}
|
|
9168
|
+
if (fixed.size >= innerSpec.axesSpec.length) throw new Error(`ColumnFilteredRecipe.wrap: filters fix all ${innerSpec.axesSpec.length} axes — at least one axis must remain`);
|
|
9169
|
+
return new ColumnFilteredRecipe(base, combined);
|
|
9170
|
+
}
|
|
9171
|
+
/**
|
|
9172
|
+
* Static counterpart to {@link wrap}: returns the resolution status of a
|
|
9173
|
+
* {@link ColumnFilteredKey} without constructing the recipe. Axis filters
|
|
9174
|
+
* do not add references — status collapses to the source's status.
|
|
9175
|
+
*/
|
|
9176
|
+
static getStatusByKey(key, opts = {}) {
|
|
9177
|
+
if (typeof key.source !== "string") throw new Error("ColumnFilteredRecipe.getStatusByKey: filtered column with non-string source");
|
|
9178
|
+
return ColumnRecipe.getStatus(key.source, opts);
|
|
9179
|
+
}
|
|
9180
|
+
id;
|
|
9181
|
+
specCache;
|
|
9182
|
+
queryCache;
|
|
9183
|
+
dataStatusCache;
|
|
9184
|
+
constructor(inner, axisFilters) {
|
|
9185
|
+
this.inner = inner;
|
|
9186
|
+
this.axisFilters = axisFilters;
|
|
9187
|
+
this.id = stringifyColumnFilteredId({
|
|
9188
|
+
source: inner.id,
|
|
9189
|
+
axisFilters
|
|
9190
|
+
});
|
|
9191
|
+
}
|
|
9192
|
+
/** Wrapped recipe — exposed so external walkers can descend. */
|
|
9193
|
+
getInner() {
|
|
9194
|
+
return this.inner;
|
|
9195
|
+
}
|
|
9196
|
+
/** Axis filters do not introduce references to other columns. */
|
|
9197
|
+
getReferencedIds() {
|
|
9198
|
+
return this.inner.getReferencedIds();
|
|
9199
|
+
}
|
|
9200
|
+
getDataStatus() {
|
|
9201
|
+
if (this.dataStatusCache === void 0) this.dataStatusCache = { value: this.inner.getDataStatus() };
|
|
9202
|
+
return this.dataStatusCache.value;
|
|
9203
|
+
}
|
|
9204
|
+
/**
|
|
9205
|
+
* Final spec — the inner spec with fixed axes removed. Indices in
|
|
9206
|
+
* `axisFilters` are positional against `inner.getSpec().axesSpec` and were
|
|
9207
|
+
* validated at {@link wrap} time.
|
|
9208
|
+
*/
|
|
9209
|
+
getSpec() {
|
|
9210
|
+
if (this.specCache === void 0) this.specCache = { value: applyAxisFilters(this.inner.getSpec(), this.axisFilters) };
|
|
9211
|
+
return this.specCache.value;
|
|
9212
|
+
}
|
|
9213
|
+
/**
|
|
9214
|
+
* Wraps the inner query in `SpecQuerySliceAxes`. Index→selector resolution
|
|
9215
|
+
* goes through the inner spec — guaranteed available since {@link wrap}
|
|
9216
|
+
* validated all indices at construction.
|
|
9217
|
+
*/
|
|
9218
|
+
getQuery() {
|
|
9219
|
+
if (this.queryCache === void 0) {
|
|
9220
|
+
const innerQuery = this.inner.getQuery();
|
|
9221
|
+
if (this.axisFilters.length === 0) this.queryCache = { value: rebrandLeafId(innerQuery, this.inner.id, this.id) };
|
|
9222
|
+
else {
|
|
9223
|
+
const innerSpec = this.inner.getSpec();
|
|
9224
|
+
this.queryCache = { value: {
|
|
9225
|
+
type: "sliceAxes",
|
|
9226
|
+
input: rebrandLeafId(innerQuery, this.inner.id, this.id),
|
|
9227
|
+
axisFilters: this.axisFilters.map(([idx, value]) => ({
|
|
9228
|
+
axisSelector: toAxisSelector(innerSpec.axesSpec[idx]),
|
|
9229
|
+
constant: value
|
|
9230
|
+
}))
|
|
9231
|
+
} };
|
|
9232
|
+
}
|
|
9233
|
+
}
|
|
9234
|
+
return this.queryCache.value;
|
|
9235
|
+
}
|
|
9236
|
+
/**
|
|
9237
|
+
* Filtered + overrides → Overridden<Filtered>. Overridden is always the
|
|
9238
|
+
* outermost layer.
|
|
9239
|
+
*/
|
|
9240
|
+
withSpecs(overrides) {
|
|
9241
|
+
return ColumnOverriddenRecipe.wrap(this, overrides);
|
|
9242
|
+
}
|
|
9243
|
+
};
|
|
9244
|
+
function toAxisSelector(axis) {
|
|
9245
|
+
const selector = {
|
|
9246
|
+
name: axis.name,
|
|
9247
|
+
type: axis.type
|
|
9248
|
+
};
|
|
9249
|
+
if (axis.domain !== void 0 && Object.keys(axis.domain).length > 0) selector.domain = axis.domain;
|
|
9250
|
+
if (axis.contextDomain !== void 0 && Object.keys(axis.contextDomain).length > 0) selector.contextDomain = axis.contextDomain;
|
|
9251
|
+
return selector;
|
|
9252
|
+
}
|
|
9253
|
+
//#endregion
|
|
9254
|
+
//#region ../../../../node_modules/.pnpm/lru-cache@11.2.2/node_modules/lru-cache/dist/esm/index.js
|
|
9255
|
+
/**
|
|
9256
|
+
* @module LRUCache
|
|
9257
|
+
*/
|
|
9258
|
+
const defaultPerf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
|
|
9259
|
+
const warned = /* @__PURE__ */ new Set();
|
|
9260
|
+
/* c8 ignore start */
|
|
9261
|
+
const PROCESS = typeof process === "object" && !!process ? process : {};
|
|
9262
|
+
/* c8 ignore start */
|
|
9263
|
+
const emitWarning = (msg, type, code, fn) => {
|
|
9264
|
+
typeof PROCESS.emitWarning === "function" ? PROCESS.emitWarning(msg, type, code, fn) : console.error(`[${code}] ${type}: ${msg}`);
|
|
9265
|
+
};
|
|
9266
|
+
let AC = globalThis.AbortController;
|
|
9267
|
+
let AS = globalThis.AbortSignal;
|
|
9268
|
+
/* c8 ignore start */
|
|
9269
|
+
if (typeof AC === "undefined") {
|
|
9270
|
+
AS = class AbortSignal {
|
|
9271
|
+
onabort;
|
|
9272
|
+
_onabort = [];
|
|
9273
|
+
reason;
|
|
9274
|
+
aborted = false;
|
|
9275
|
+
addEventListener(_, fn) {
|
|
9276
|
+
this._onabort.push(fn);
|
|
9277
|
+
}
|
|
9278
|
+
};
|
|
9279
|
+
AC = class AbortController {
|
|
9280
|
+
constructor() {
|
|
9281
|
+
warnACPolyfill();
|
|
9282
|
+
}
|
|
9283
|
+
signal = new AS();
|
|
9284
|
+
abort(reason) {
|
|
9285
|
+
if (this.signal.aborted) return;
|
|
9286
|
+
this.signal.reason = reason;
|
|
9287
|
+
this.signal.aborted = true;
|
|
9288
|
+
for (const fn of this.signal._onabort) fn(reason);
|
|
9289
|
+
this.signal.onabort?.(reason);
|
|
9290
|
+
}
|
|
9291
|
+
};
|
|
9292
|
+
let printACPolyfillWarning = PROCESS.env?.LRU_CACHE_IGNORE_AC_WARNING !== "1";
|
|
9293
|
+
const warnACPolyfill = () => {
|
|
9294
|
+
if (!printACPolyfillWarning) return;
|
|
9295
|
+
printACPolyfillWarning = false;
|
|
9296
|
+
emitWarning("AbortController is not defined. If using lru-cache in node 14, load an AbortController polyfill from the `node-abort-controller` package. A minimal polyfill is provided for use by LRUCache.fetch(), but it should not be relied upon in other contexts (eg, passing it to other APIs that use AbortController/AbortSignal might have undesirable effects). You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.", "NO_ABORT_CONTROLLER", "ENOTSUP", warnACPolyfill);
|
|
9297
|
+
};
|
|
9298
|
+
}
|
|
9299
|
+
/* c8 ignore stop */
|
|
9300
|
+
const shouldWarn = (code) => !warned.has(code);
|
|
9301
|
+
const isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
|
|
9302
|
+
/* c8 ignore start */
|
|
9303
|
+
const getUintArray = (max) => !isPosInt(max) ? null : max <= Math.pow(2, 8) ? Uint8Array : max <= Math.pow(2, 16) ? Uint16Array : max <= Math.pow(2, 32) ? Uint32Array : max <= Number.MAX_SAFE_INTEGER ? ZeroArray : null;
|
|
9304
|
+
/* c8 ignore stop */
|
|
9305
|
+
var ZeroArray = class extends Array {
|
|
9306
|
+
constructor(size) {
|
|
9307
|
+
super(size);
|
|
9308
|
+
this.fill(0);
|
|
9309
|
+
}
|
|
9310
|
+
};
|
|
9311
|
+
var Stack = class Stack {
|
|
9312
|
+
heap;
|
|
9313
|
+
length;
|
|
9314
|
+
static #constructing = false;
|
|
9315
|
+
static create(max) {
|
|
9316
|
+
const HeapCls = getUintArray(max);
|
|
9317
|
+
if (!HeapCls) return [];
|
|
9318
|
+
Stack.#constructing = true;
|
|
9319
|
+
const s = new Stack(max, HeapCls);
|
|
9320
|
+
Stack.#constructing = false;
|
|
9321
|
+
return s;
|
|
9322
|
+
}
|
|
9323
|
+
constructor(max, HeapCls) {
|
|
9324
|
+
/* c8 ignore start */
|
|
9325
|
+
if (!Stack.#constructing) throw new TypeError("instantiate Stack using Stack.create(n)");
|
|
9326
|
+
/* c8 ignore stop */
|
|
9327
|
+
this.heap = new HeapCls(max);
|
|
9328
|
+
this.length = 0;
|
|
9329
|
+
}
|
|
9330
|
+
push(n) {
|
|
9331
|
+
this.heap[this.length++] = n;
|
|
9332
|
+
}
|
|
9333
|
+
pop() {
|
|
9334
|
+
return this.heap[--this.length];
|
|
9335
|
+
}
|
|
9336
|
+
};
|
|
9337
|
+
/**
|
|
9338
|
+
* Default export, the thing you're using this module to get.
|
|
9339
|
+
*
|
|
9340
|
+
* The `K` and `V` types define the key and value types, respectively. The
|
|
9341
|
+
* optional `FC` type defines the type of the `context` object passed to
|
|
9342
|
+
* `cache.fetch()` and `cache.memo()`.
|
|
9343
|
+
*
|
|
9344
|
+
* Keys and values **must not** be `null` or `undefined`.
|
|
9345
|
+
*
|
|
9346
|
+
* All properties from the options object (with the exception of `max`,
|
|
9347
|
+
* `maxSize`, `fetchMethod`, `memoMethod`, `dispose` and `disposeAfter`) are
|
|
9348
|
+
* added as normal public members. (The listed options are read-only getters.)
|
|
9349
|
+
*
|
|
9350
|
+
* Changing any of these will alter the defaults for subsequent method calls.
|
|
9351
|
+
*/
|
|
9352
|
+
var LRUCache = class LRUCache {
|
|
9353
|
+
#max;
|
|
9354
|
+
#maxSize;
|
|
9355
|
+
#dispose;
|
|
9356
|
+
#onInsert;
|
|
9357
|
+
#disposeAfter;
|
|
9358
|
+
#fetchMethod;
|
|
9359
|
+
#memoMethod;
|
|
9360
|
+
#perf;
|
|
9361
|
+
/**
|
|
9362
|
+
* {@link LRUCache.OptionsBase.perf}
|
|
9363
|
+
*/
|
|
9364
|
+
get perf() {
|
|
9365
|
+
return this.#perf;
|
|
9366
|
+
}
|
|
9367
|
+
/**
|
|
9368
|
+
* {@link LRUCache.OptionsBase.ttl}
|
|
9369
|
+
*/
|
|
9370
|
+
ttl;
|
|
9371
|
+
/**
|
|
9372
|
+
* {@link LRUCache.OptionsBase.ttlResolution}
|
|
9373
|
+
*/
|
|
9374
|
+
ttlResolution;
|
|
9375
|
+
/**
|
|
9376
|
+
* {@link LRUCache.OptionsBase.ttlAutopurge}
|
|
9377
|
+
*/
|
|
9378
|
+
ttlAutopurge;
|
|
9379
|
+
/**
|
|
9380
|
+
* {@link LRUCache.OptionsBase.updateAgeOnGet}
|
|
9381
|
+
*/
|
|
9382
|
+
updateAgeOnGet;
|
|
9383
|
+
/**
|
|
9384
|
+
* {@link LRUCache.OptionsBase.updateAgeOnHas}
|
|
9385
|
+
*/
|
|
9386
|
+
updateAgeOnHas;
|
|
9387
|
+
/**
|
|
9388
|
+
* {@link LRUCache.OptionsBase.allowStale}
|
|
9389
|
+
*/
|
|
9390
|
+
allowStale;
|
|
9391
|
+
/**
|
|
9392
|
+
* {@link LRUCache.OptionsBase.noDisposeOnSet}
|
|
9393
|
+
*/
|
|
9394
|
+
noDisposeOnSet;
|
|
9395
|
+
/**
|
|
9396
|
+
* {@link LRUCache.OptionsBase.noUpdateTTL}
|
|
9397
|
+
*/
|
|
9398
|
+
noUpdateTTL;
|
|
9399
|
+
/**
|
|
9400
|
+
* {@link LRUCache.OptionsBase.maxEntrySize}
|
|
9401
|
+
*/
|
|
9402
|
+
maxEntrySize;
|
|
9403
|
+
/**
|
|
9404
|
+
* {@link LRUCache.OptionsBase.sizeCalculation}
|
|
9405
|
+
*/
|
|
9406
|
+
sizeCalculation;
|
|
9407
|
+
/**
|
|
9408
|
+
* {@link LRUCache.OptionsBase.noDeleteOnFetchRejection}
|
|
9409
|
+
*/
|
|
9410
|
+
noDeleteOnFetchRejection;
|
|
9411
|
+
/**
|
|
9412
|
+
* {@link LRUCache.OptionsBase.noDeleteOnStaleGet}
|
|
9413
|
+
*/
|
|
9414
|
+
noDeleteOnStaleGet;
|
|
9415
|
+
/**
|
|
9416
|
+
* {@link LRUCache.OptionsBase.allowStaleOnFetchAbort}
|
|
9417
|
+
*/
|
|
9418
|
+
allowStaleOnFetchAbort;
|
|
9419
|
+
/**
|
|
9420
|
+
* {@link LRUCache.OptionsBase.allowStaleOnFetchRejection}
|
|
9421
|
+
*/
|
|
9422
|
+
allowStaleOnFetchRejection;
|
|
9423
|
+
/**
|
|
9424
|
+
* {@link LRUCache.OptionsBase.ignoreFetchAbort}
|
|
9425
|
+
*/
|
|
9426
|
+
ignoreFetchAbort;
|
|
9427
|
+
#size;
|
|
9428
|
+
#calculatedSize;
|
|
9429
|
+
#keyMap;
|
|
9430
|
+
#keyList;
|
|
9431
|
+
#valList;
|
|
9432
|
+
#next;
|
|
9433
|
+
#prev;
|
|
9434
|
+
#head;
|
|
9435
|
+
#tail;
|
|
9436
|
+
#free;
|
|
9437
|
+
#disposed;
|
|
9438
|
+
#sizes;
|
|
9439
|
+
#starts;
|
|
9440
|
+
#ttls;
|
|
9441
|
+
#hasDispose;
|
|
9442
|
+
#hasFetchMethod;
|
|
9443
|
+
#hasDisposeAfter;
|
|
9444
|
+
#hasOnInsert;
|
|
9445
|
+
/**
|
|
9446
|
+
* Do not call this method unless you need to inspect the
|
|
9447
|
+
* inner workings of the cache. If anything returned by this
|
|
9448
|
+
* object is modified in any way, strange breakage may occur.
|
|
9449
|
+
*
|
|
9450
|
+
* These fields are private for a reason!
|
|
9451
|
+
*
|
|
9452
|
+
* @internal
|
|
9453
|
+
*/
|
|
9454
|
+
static unsafeExposeInternals(c) {
|
|
9455
|
+
return {
|
|
9456
|
+
starts: c.#starts,
|
|
9457
|
+
ttls: c.#ttls,
|
|
9458
|
+
sizes: c.#sizes,
|
|
9459
|
+
keyMap: c.#keyMap,
|
|
9460
|
+
keyList: c.#keyList,
|
|
9461
|
+
valList: c.#valList,
|
|
9462
|
+
next: c.#next,
|
|
9463
|
+
prev: c.#prev,
|
|
9464
|
+
get head() {
|
|
9465
|
+
return c.#head;
|
|
9466
|
+
},
|
|
9467
|
+
get tail() {
|
|
9468
|
+
return c.#tail;
|
|
9469
|
+
},
|
|
9470
|
+
free: c.#free,
|
|
9471
|
+
isBackgroundFetch: (p) => c.#isBackgroundFetch(p),
|
|
9472
|
+
backgroundFetch: (k, index, options, context) => c.#backgroundFetch(k, index, options, context),
|
|
9473
|
+
moveToTail: (index) => c.#moveToTail(index),
|
|
9474
|
+
indexes: (options) => c.#indexes(options),
|
|
9475
|
+
rindexes: (options) => c.#rindexes(options),
|
|
9476
|
+
isStale: (index) => c.#isStale(index)
|
|
9477
|
+
};
|
|
9478
|
+
}
|
|
9479
|
+
/**
|
|
9480
|
+
* {@link LRUCache.OptionsBase.max} (read-only)
|
|
9481
|
+
*/
|
|
9482
|
+
get max() {
|
|
9483
|
+
return this.#max;
|
|
9484
|
+
}
|
|
9485
|
+
/**
|
|
9486
|
+
* {@link LRUCache.OptionsBase.maxSize} (read-only)
|
|
9487
|
+
*/
|
|
9488
|
+
get maxSize() {
|
|
9489
|
+
return this.#maxSize;
|
|
9490
|
+
}
|
|
9491
|
+
/**
|
|
9492
|
+
* The total computed size of items in the cache (read-only)
|
|
9493
|
+
*/
|
|
9494
|
+
get calculatedSize() {
|
|
9495
|
+
return this.#calculatedSize;
|
|
9496
|
+
}
|
|
9497
|
+
/**
|
|
9498
|
+
* The number of items stored in the cache (read-only)
|
|
9499
|
+
*/
|
|
9500
|
+
get size() {
|
|
9501
|
+
return this.#size;
|
|
9502
|
+
}
|
|
9503
|
+
/**
|
|
9504
|
+
* {@link LRUCache.OptionsBase.fetchMethod} (read-only)
|
|
9505
|
+
*/
|
|
9506
|
+
get fetchMethod() {
|
|
9507
|
+
return this.#fetchMethod;
|
|
9508
|
+
}
|
|
9509
|
+
get memoMethod() {
|
|
9510
|
+
return this.#memoMethod;
|
|
9511
|
+
}
|
|
9512
|
+
/**
|
|
9513
|
+
* {@link LRUCache.OptionsBase.dispose} (read-only)
|
|
9514
|
+
*/
|
|
9515
|
+
get dispose() {
|
|
9516
|
+
return this.#dispose;
|
|
9517
|
+
}
|
|
9518
|
+
/**
|
|
9519
|
+
* {@link LRUCache.OptionsBase.onInsert} (read-only)
|
|
9520
|
+
*/
|
|
9521
|
+
get onInsert() {
|
|
9522
|
+
return this.#onInsert;
|
|
9523
|
+
}
|
|
9524
|
+
/**
|
|
9525
|
+
* {@link LRUCache.OptionsBase.disposeAfter} (read-only)
|
|
9526
|
+
*/
|
|
9527
|
+
get disposeAfter() {
|
|
9528
|
+
return this.#disposeAfter;
|
|
9529
|
+
}
|
|
9530
|
+
constructor(options) {
|
|
9531
|
+
const { max = 0, ttl, ttlResolution = 1, ttlAutopurge, updateAgeOnGet, updateAgeOnHas, allowStale, dispose, onInsert, disposeAfter, noDisposeOnSet, noUpdateTTL, maxSize = 0, maxEntrySize = 0, sizeCalculation, fetchMethod, memoMethod, noDeleteOnFetchRejection, noDeleteOnStaleGet, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort, perf } = options;
|
|
9532
|
+
if (perf !== void 0) {
|
|
9533
|
+
if (typeof perf?.now !== "function") throw new TypeError("perf option must have a now() method if specified");
|
|
9534
|
+
}
|
|
9535
|
+
this.#perf = perf ?? defaultPerf;
|
|
9536
|
+
if (max !== 0 && !isPosInt(max)) throw new TypeError("max option must be a nonnegative integer");
|
|
9537
|
+
const UintArray = max ? getUintArray(max) : Array;
|
|
9538
|
+
if (!UintArray) throw new Error("invalid max value: " + max);
|
|
9539
|
+
this.#max = max;
|
|
9540
|
+
this.#maxSize = maxSize;
|
|
9541
|
+
this.maxEntrySize = maxEntrySize || this.#maxSize;
|
|
9542
|
+
this.sizeCalculation = sizeCalculation;
|
|
9543
|
+
if (this.sizeCalculation) {
|
|
9544
|
+
if (!this.#maxSize && !this.maxEntrySize) throw new TypeError("cannot set sizeCalculation without setting maxSize or maxEntrySize");
|
|
9545
|
+
if (typeof this.sizeCalculation !== "function") throw new TypeError("sizeCalculation set to non-function");
|
|
9546
|
+
}
|
|
9547
|
+
if (memoMethod !== void 0 && typeof memoMethod !== "function") throw new TypeError("memoMethod must be a function if defined");
|
|
9548
|
+
this.#memoMethod = memoMethod;
|
|
9549
|
+
if (fetchMethod !== void 0 && typeof fetchMethod !== "function") throw new TypeError("fetchMethod must be a function if specified");
|
|
9550
|
+
this.#fetchMethod = fetchMethod;
|
|
9551
|
+
this.#hasFetchMethod = !!fetchMethod;
|
|
9552
|
+
this.#keyMap = /* @__PURE__ */ new Map();
|
|
9553
|
+
this.#keyList = new Array(max).fill(void 0);
|
|
9554
|
+
this.#valList = new Array(max).fill(void 0);
|
|
9555
|
+
this.#next = new UintArray(max);
|
|
9556
|
+
this.#prev = new UintArray(max);
|
|
9557
|
+
this.#head = 0;
|
|
9558
|
+
this.#tail = 0;
|
|
9559
|
+
this.#free = Stack.create(max);
|
|
9560
|
+
this.#size = 0;
|
|
9561
|
+
this.#calculatedSize = 0;
|
|
9562
|
+
if (typeof dispose === "function") this.#dispose = dispose;
|
|
9563
|
+
if (typeof onInsert === "function") this.#onInsert = onInsert;
|
|
9564
|
+
if (typeof disposeAfter === "function") {
|
|
9565
|
+
this.#disposeAfter = disposeAfter;
|
|
9566
|
+
this.#disposed = [];
|
|
9567
|
+
} else {
|
|
9568
|
+
this.#disposeAfter = void 0;
|
|
9569
|
+
this.#disposed = void 0;
|
|
9570
|
+
}
|
|
9571
|
+
this.#hasDispose = !!this.#dispose;
|
|
9572
|
+
this.#hasOnInsert = !!this.#onInsert;
|
|
9573
|
+
this.#hasDisposeAfter = !!this.#disposeAfter;
|
|
9574
|
+
this.noDisposeOnSet = !!noDisposeOnSet;
|
|
9575
|
+
this.noUpdateTTL = !!noUpdateTTL;
|
|
9576
|
+
this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection;
|
|
9577
|
+
this.allowStaleOnFetchRejection = !!allowStaleOnFetchRejection;
|
|
9578
|
+
this.allowStaleOnFetchAbort = !!allowStaleOnFetchAbort;
|
|
9579
|
+
this.ignoreFetchAbort = !!ignoreFetchAbort;
|
|
9580
|
+
if (this.maxEntrySize !== 0) {
|
|
9581
|
+
if (this.#maxSize !== 0) {
|
|
9582
|
+
if (!isPosInt(this.#maxSize)) throw new TypeError("maxSize must be a positive integer if specified");
|
|
9583
|
+
}
|
|
9584
|
+
if (!isPosInt(this.maxEntrySize)) throw new TypeError("maxEntrySize must be a positive integer if specified");
|
|
9585
|
+
this.#initializeSizeTracking();
|
|
9586
|
+
}
|
|
9587
|
+
this.allowStale = !!allowStale;
|
|
9588
|
+
this.noDeleteOnStaleGet = !!noDeleteOnStaleGet;
|
|
9589
|
+
this.updateAgeOnGet = !!updateAgeOnGet;
|
|
9590
|
+
this.updateAgeOnHas = !!updateAgeOnHas;
|
|
9591
|
+
this.ttlResolution = isPosInt(ttlResolution) || ttlResolution === 0 ? ttlResolution : 1;
|
|
9592
|
+
this.ttlAutopurge = !!ttlAutopurge;
|
|
9593
|
+
this.ttl = ttl || 0;
|
|
9594
|
+
if (this.ttl) {
|
|
9595
|
+
if (!isPosInt(this.ttl)) throw new TypeError("ttl must be a positive integer if specified");
|
|
9596
|
+
this.#initializeTTLTracking();
|
|
9597
|
+
}
|
|
9598
|
+
if (this.#max === 0 && this.ttl === 0 && this.#maxSize === 0) throw new TypeError("At least one of max, maxSize, or ttl is required");
|
|
9599
|
+
if (!this.ttlAutopurge && !this.#max && !this.#maxSize) {
|
|
9600
|
+
const code = "LRU_CACHE_UNBOUNDED";
|
|
9601
|
+
if (shouldWarn(code)) {
|
|
9602
|
+
warned.add(code);
|
|
9603
|
+
emitWarning("TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.", "UnboundedCacheWarning", code, LRUCache);
|
|
9604
|
+
}
|
|
9605
|
+
}
|
|
9606
|
+
}
|
|
9607
|
+
/**
|
|
9608
|
+
* Return the number of ms left in the item's TTL. If item is not in cache,
|
|
9609
|
+
* returns `0`. Returns `Infinity` if item is in cache without a defined TTL.
|
|
9610
|
+
*/
|
|
9611
|
+
getRemainingTTL(key) {
|
|
9612
|
+
return this.#keyMap.has(key) ? Infinity : 0;
|
|
9613
|
+
}
|
|
9614
|
+
#initializeTTLTracking() {
|
|
9615
|
+
const ttls = new ZeroArray(this.#max);
|
|
9616
|
+
const starts = new ZeroArray(this.#max);
|
|
9617
|
+
this.#ttls = ttls;
|
|
9618
|
+
this.#starts = starts;
|
|
9619
|
+
this.#setItemTTL = (index, ttl, start = this.#perf.now()) => {
|
|
9620
|
+
starts[index] = ttl !== 0 ? start : 0;
|
|
9621
|
+
ttls[index] = ttl;
|
|
9622
|
+
if (ttl !== 0 && this.ttlAutopurge) {
|
|
9623
|
+
const t = setTimeout(() => {
|
|
9624
|
+
if (this.#isStale(index)) this.#delete(this.#keyList[index], "expire");
|
|
9625
|
+
}, ttl + 1);
|
|
9626
|
+
/* c8 ignore start */
|
|
9627
|
+
if (t.unref) t.unref();
|
|
9628
|
+
}
|
|
9629
|
+
};
|
|
9630
|
+
this.#updateItemAge = (index) => {
|
|
9631
|
+
starts[index] = ttls[index] !== 0 ? this.#perf.now() : 0;
|
|
9632
|
+
};
|
|
9633
|
+
this.#statusTTL = (status, index) => {
|
|
9634
|
+
if (ttls[index]) {
|
|
9635
|
+
const ttl = ttls[index];
|
|
9636
|
+
const start = starts[index];
|
|
9637
|
+
/* c8 ignore next */
|
|
9638
|
+
if (!ttl || !start) return;
|
|
9639
|
+
status.ttl = ttl;
|
|
9640
|
+
status.start = start;
|
|
9641
|
+
status.now = cachedNow || getNow();
|
|
9642
|
+
status.remainingTTL = ttl - (status.now - start);
|
|
9643
|
+
}
|
|
9644
|
+
};
|
|
9645
|
+
let cachedNow = 0;
|
|
9646
|
+
const getNow = () => {
|
|
9647
|
+
const n = this.#perf.now();
|
|
9648
|
+
if (this.ttlResolution > 0) {
|
|
9649
|
+
cachedNow = n;
|
|
9650
|
+
const t = setTimeout(() => cachedNow = 0, this.ttlResolution);
|
|
9651
|
+
/* c8 ignore start */
|
|
9652
|
+
if (t.unref) t.unref();
|
|
9653
|
+
}
|
|
9654
|
+
return n;
|
|
9655
|
+
};
|
|
9656
|
+
this.getRemainingTTL = (key) => {
|
|
9657
|
+
const index = this.#keyMap.get(key);
|
|
9658
|
+
if (index === void 0) return 0;
|
|
9659
|
+
const ttl = ttls[index];
|
|
9660
|
+
const start = starts[index];
|
|
9661
|
+
if (!ttl || !start) return Infinity;
|
|
9662
|
+
return ttl - ((cachedNow || getNow()) - start);
|
|
9663
|
+
};
|
|
9664
|
+
this.#isStale = (index) => {
|
|
9665
|
+
const s = starts[index];
|
|
9666
|
+
const t = ttls[index];
|
|
9667
|
+
return !!t && !!s && (cachedNow || getNow()) - s > t;
|
|
9668
|
+
};
|
|
9669
|
+
}
|
|
9670
|
+
#updateItemAge = () => {};
|
|
9671
|
+
#statusTTL = () => {};
|
|
9672
|
+
#setItemTTL = () => {};
|
|
9673
|
+
/* c8 ignore stop */
|
|
9674
|
+
#isStale = () => false;
|
|
9675
|
+
#initializeSizeTracking() {
|
|
9676
|
+
const sizes = new ZeroArray(this.#max);
|
|
9677
|
+
this.#calculatedSize = 0;
|
|
9678
|
+
this.#sizes = sizes;
|
|
9679
|
+
this.#removeItemSize = (index) => {
|
|
9680
|
+
this.#calculatedSize -= sizes[index];
|
|
9681
|
+
sizes[index] = 0;
|
|
9682
|
+
};
|
|
9683
|
+
this.#requireSize = (k, v, size, sizeCalculation) => {
|
|
9684
|
+
if (this.#isBackgroundFetch(v)) return 0;
|
|
9685
|
+
if (!isPosInt(size)) if (sizeCalculation) {
|
|
9686
|
+
if (typeof sizeCalculation !== "function") throw new TypeError("sizeCalculation must be a function");
|
|
9687
|
+
size = sizeCalculation(v, k);
|
|
9688
|
+
if (!isPosInt(size)) throw new TypeError("sizeCalculation return invalid (expect positive integer)");
|
|
9689
|
+
} else throw new TypeError("invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set.");
|
|
9690
|
+
return size;
|
|
9691
|
+
};
|
|
9692
|
+
this.#addItemSize = (index, size, status) => {
|
|
9693
|
+
sizes[index] = size;
|
|
9694
|
+
if (this.#maxSize) {
|
|
9695
|
+
const maxSize = this.#maxSize - sizes[index];
|
|
9696
|
+
while (this.#calculatedSize > maxSize) this.#evict(true);
|
|
9697
|
+
}
|
|
9698
|
+
this.#calculatedSize += sizes[index];
|
|
9699
|
+
if (status) {
|
|
9700
|
+
status.entrySize = size;
|
|
9701
|
+
status.totalCalculatedSize = this.#calculatedSize;
|
|
9702
|
+
}
|
|
9703
|
+
};
|
|
9704
|
+
}
|
|
9705
|
+
#removeItemSize = (_i) => {};
|
|
9706
|
+
#addItemSize = (_i, _s, _st) => {};
|
|
9707
|
+
#requireSize = (_k, _v, size, sizeCalculation) => {
|
|
9708
|
+
if (size || sizeCalculation) throw new TypeError("cannot set size without setting maxSize or maxEntrySize on cache");
|
|
9709
|
+
return 0;
|
|
9710
|
+
};
|
|
9711
|
+
*#indexes({ allowStale = this.allowStale } = {}) {
|
|
9712
|
+
if (this.#size) for (let i = this.#tail;;) {
|
|
9713
|
+
if (!this.#isValidIndex(i)) break;
|
|
9714
|
+
if (allowStale || !this.#isStale(i)) yield i;
|
|
9715
|
+
if (i === this.#head) break;
|
|
9716
|
+
else i = this.#prev[i];
|
|
9717
|
+
}
|
|
9718
|
+
}
|
|
9719
|
+
*#rindexes({ allowStale = this.allowStale } = {}) {
|
|
9720
|
+
if (this.#size) for (let i = this.#head;;) {
|
|
9721
|
+
if (!this.#isValidIndex(i)) break;
|
|
9722
|
+
if (allowStale || !this.#isStale(i)) yield i;
|
|
9723
|
+
if (i === this.#tail) break;
|
|
9724
|
+
else i = this.#next[i];
|
|
9725
|
+
}
|
|
9726
|
+
}
|
|
9727
|
+
#isValidIndex(index) {
|
|
9728
|
+
return index !== void 0 && this.#keyMap.get(this.#keyList[index]) === index;
|
|
9729
|
+
}
|
|
9730
|
+
/**
|
|
9731
|
+
* Return a generator yielding `[key, value]` pairs,
|
|
9732
|
+
* in order from most recently used to least recently used.
|
|
9733
|
+
*/
|
|
9734
|
+
*entries() {
|
|
9735
|
+
for (const i of this.#indexes()) if (this.#valList[i] !== void 0 && this.#keyList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield [this.#keyList[i], this.#valList[i]];
|
|
9736
|
+
}
|
|
9737
|
+
/**
|
|
9738
|
+
* Inverse order version of {@link LRUCache.entries}
|
|
9739
|
+
*
|
|
9740
|
+
* Return a generator yielding `[key, value]` pairs,
|
|
9741
|
+
* in order from least recently used to most recently used.
|
|
9742
|
+
*/
|
|
9743
|
+
*rentries() {
|
|
9744
|
+
for (const i of this.#rindexes()) if (this.#valList[i] !== void 0 && this.#keyList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield [this.#keyList[i], this.#valList[i]];
|
|
9745
|
+
}
|
|
9746
|
+
/**
|
|
9747
|
+
* Return a generator yielding the keys in the cache,
|
|
9748
|
+
* in order from most recently used to least recently used.
|
|
9749
|
+
*/
|
|
9750
|
+
*keys() {
|
|
9751
|
+
for (const i of this.#indexes()) {
|
|
9752
|
+
const k = this.#keyList[i];
|
|
9753
|
+
if (k !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield k;
|
|
9754
|
+
}
|
|
9755
|
+
}
|
|
9756
|
+
/**
|
|
9757
|
+
* Inverse order version of {@link LRUCache.keys}
|
|
9758
|
+
*
|
|
9759
|
+
* Return a generator yielding the keys in the cache,
|
|
9760
|
+
* in order from least recently used to most recently used.
|
|
9761
|
+
*/
|
|
9762
|
+
*rkeys() {
|
|
9763
|
+
for (const i of this.#rindexes()) {
|
|
9764
|
+
const k = this.#keyList[i];
|
|
9765
|
+
if (k !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield k;
|
|
9766
|
+
}
|
|
9767
|
+
}
|
|
9768
|
+
/**
|
|
9769
|
+
* Return a generator yielding the values in the cache,
|
|
9770
|
+
* in order from most recently used to least recently used.
|
|
9771
|
+
*/
|
|
9772
|
+
*values() {
|
|
9773
|
+
for (const i of this.#indexes()) if (this.#valList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield this.#valList[i];
|
|
9774
|
+
}
|
|
9775
|
+
/**
|
|
9776
|
+
* Inverse order version of {@link LRUCache.values}
|
|
9777
|
+
*
|
|
9778
|
+
* Return a generator yielding the values in the cache,
|
|
9779
|
+
* in order from least recently used to most recently used.
|
|
9780
|
+
*/
|
|
9781
|
+
*rvalues() {
|
|
9782
|
+
for (const i of this.#rindexes()) if (this.#valList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield this.#valList[i];
|
|
9783
|
+
}
|
|
9784
|
+
/**
|
|
9785
|
+
* Iterating over the cache itself yields the same results as
|
|
9786
|
+
* {@link LRUCache.entries}
|
|
9787
|
+
*/
|
|
9788
|
+
[Symbol.iterator]() {
|
|
9789
|
+
return this.entries();
|
|
9790
|
+
}
|
|
9791
|
+
/**
|
|
9792
|
+
* A String value that is used in the creation of the default string
|
|
9793
|
+
* description of an object. Called by the built-in method
|
|
9794
|
+
* `Object.prototype.toString`.
|
|
9795
|
+
*/
|
|
9796
|
+
[Symbol.toStringTag] = "LRUCache";
|
|
9797
|
+
/**
|
|
9798
|
+
* Find a value for which the supplied fn method returns a truthy value,
|
|
9799
|
+
* similar to `Array.find()`. fn is called as `fn(value, key, cache)`.
|
|
9800
|
+
*/
|
|
9801
|
+
find(fn, getOptions = {}) {
|
|
9802
|
+
for (const i of this.#indexes()) {
|
|
9803
|
+
const v = this.#valList[i];
|
|
9804
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
9805
|
+
if (value === void 0) continue;
|
|
9806
|
+
if (fn(value, this.#keyList[i], this)) return this.get(this.#keyList[i], getOptions);
|
|
9807
|
+
}
|
|
9808
|
+
}
|
|
9809
|
+
/**
|
|
9810
|
+
* Call the supplied function on each item in the cache, in order from most
|
|
9811
|
+
* recently used to least recently used.
|
|
9812
|
+
*
|
|
9813
|
+
* `fn` is called as `fn(value, key, cache)`.
|
|
9814
|
+
*
|
|
9815
|
+
* If `thisp` is provided, function will be called in the `this`-context of
|
|
9816
|
+
* the provided object, or the cache if no `thisp` object is provided.
|
|
9817
|
+
*
|
|
9818
|
+
* Does not update age or recenty of use, or iterate over stale values.
|
|
9819
|
+
*/
|
|
9820
|
+
forEach(fn, thisp = this) {
|
|
9821
|
+
for (const i of this.#indexes()) {
|
|
9822
|
+
const v = this.#valList[i];
|
|
9823
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
9824
|
+
if (value === void 0) continue;
|
|
9825
|
+
fn.call(thisp, value, this.#keyList[i], this);
|
|
9826
|
+
}
|
|
9827
|
+
}
|
|
9828
|
+
/**
|
|
9829
|
+
* The same as {@link LRUCache.forEach} but items are iterated over in
|
|
9830
|
+
* reverse order. (ie, less recently used items are iterated over first.)
|
|
9831
|
+
*/
|
|
9832
|
+
rforEach(fn, thisp = this) {
|
|
9833
|
+
for (const i of this.#rindexes()) {
|
|
9834
|
+
const v = this.#valList[i];
|
|
9835
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
9836
|
+
if (value === void 0) continue;
|
|
9837
|
+
fn.call(thisp, value, this.#keyList[i], this);
|
|
9838
|
+
}
|
|
9839
|
+
}
|
|
9840
|
+
/**
|
|
9841
|
+
* Delete any stale entries. Returns true if anything was removed,
|
|
9842
|
+
* false otherwise.
|
|
9843
|
+
*/
|
|
9844
|
+
purgeStale() {
|
|
9845
|
+
let deleted = false;
|
|
9846
|
+
for (const i of this.#rindexes({ allowStale: true })) if (this.#isStale(i)) {
|
|
9847
|
+
this.#delete(this.#keyList[i], "expire");
|
|
9848
|
+
deleted = true;
|
|
9849
|
+
}
|
|
9850
|
+
return deleted;
|
|
9851
|
+
}
|
|
9852
|
+
/**
|
|
9853
|
+
* Get the extended info about a given entry, to get its value, size, and
|
|
9854
|
+
* TTL info simultaneously. Returns `undefined` if the key is not present.
|
|
9855
|
+
*
|
|
9856
|
+
* Unlike {@link LRUCache#dump}, which is designed to be portable and survive
|
|
9857
|
+
* serialization, the `start` value is always the current timestamp, and the
|
|
9858
|
+
* `ttl` is a calculated remaining time to live (negative if expired).
|
|
9859
|
+
*
|
|
9860
|
+
* Always returns stale values, if their info is found in the cache, so be
|
|
9861
|
+
* sure to check for expirations (ie, a negative {@link LRUCache.Entry#ttl})
|
|
9862
|
+
* if relevant.
|
|
9863
|
+
*/
|
|
9864
|
+
info(key) {
|
|
9865
|
+
const i = this.#keyMap.get(key);
|
|
9866
|
+
if (i === void 0) return void 0;
|
|
9867
|
+
const v = this.#valList[i];
|
|
9868
|
+
/* c8 ignore start - this isn't tested for the info function,
|
|
9869
|
+
* but it's the same logic as found in other places. */
|
|
9870
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
9871
|
+
if (value === void 0) return void 0;
|
|
9872
|
+
/* c8 ignore end */
|
|
9873
|
+
const entry = { value };
|
|
9874
|
+
if (this.#ttls && this.#starts) {
|
|
9875
|
+
const ttl = this.#ttls[i];
|
|
9876
|
+
const start = this.#starts[i];
|
|
9877
|
+
if (ttl && start) {
|
|
9878
|
+
entry.ttl = ttl - (this.#perf.now() - start);
|
|
9879
|
+
entry.start = Date.now();
|
|
9880
|
+
}
|
|
9881
|
+
}
|
|
9882
|
+
if (this.#sizes) entry.size = this.#sizes[i];
|
|
9883
|
+
return entry;
|
|
9884
|
+
}
|
|
9885
|
+
/**
|
|
9886
|
+
* Return an array of [key, {@link LRUCache.Entry}] tuples which can be
|
|
9887
|
+
* passed to {@link LRUCache#load}.
|
|
9888
|
+
*
|
|
9889
|
+
* The `start` fields are calculated relative to a portable `Date.now()`
|
|
9890
|
+
* timestamp, even if `performance.now()` is available.
|
|
9891
|
+
*
|
|
9892
|
+
* Stale entries are always included in the `dump`, even if
|
|
9893
|
+
* {@link LRUCache.OptionsBase.allowStale} is false.
|
|
9894
|
+
*
|
|
9895
|
+
* Note: this returns an actual array, not a generator, so it can be more
|
|
9896
|
+
* easily passed around.
|
|
9897
|
+
*/
|
|
9898
|
+
dump() {
|
|
9899
|
+
const arr = [];
|
|
9900
|
+
for (const i of this.#indexes({ allowStale: true })) {
|
|
9901
|
+
const key = this.#keyList[i];
|
|
9902
|
+
const v = this.#valList[i];
|
|
9903
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
9904
|
+
if (value === void 0 || key === void 0) continue;
|
|
9905
|
+
const entry = { value };
|
|
9906
|
+
if (this.#ttls && this.#starts) {
|
|
9907
|
+
entry.ttl = this.#ttls[i];
|
|
9908
|
+
const age = this.#perf.now() - this.#starts[i];
|
|
9909
|
+
entry.start = Math.floor(Date.now() - age);
|
|
9910
|
+
}
|
|
9911
|
+
if (this.#sizes) entry.size = this.#sizes[i];
|
|
9912
|
+
arr.unshift([key, entry]);
|
|
9913
|
+
}
|
|
9914
|
+
return arr;
|
|
9915
|
+
}
|
|
9916
|
+
/**
|
|
9917
|
+
* Reset the cache and load in the items in entries in the order listed.
|
|
9918
|
+
*
|
|
9919
|
+
* The shape of the resulting cache may be different if the same options are
|
|
9920
|
+
* not used in both caches.
|
|
9921
|
+
*
|
|
9922
|
+
* The `start` fields are assumed to be calculated relative to a portable
|
|
9923
|
+
* `Date.now()` timestamp, even if `performance.now()` is available.
|
|
9924
|
+
*/
|
|
9925
|
+
load(arr) {
|
|
9926
|
+
this.clear();
|
|
9927
|
+
for (const [key, entry] of arr) {
|
|
9928
|
+
if (entry.start) {
|
|
9929
|
+
const age = Date.now() - entry.start;
|
|
9930
|
+
entry.start = this.#perf.now() - age;
|
|
9931
|
+
}
|
|
9932
|
+
this.set(key, entry.value, entry);
|
|
9933
|
+
}
|
|
9934
|
+
}
|
|
9935
|
+
/**
|
|
9936
|
+
* Add a value to the cache.
|
|
9937
|
+
*
|
|
9938
|
+
* Note: if `undefined` is specified as a value, this is an alias for
|
|
9939
|
+
* {@link LRUCache#delete}
|
|
9940
|
+
*
|
|
9941
|
+
* Fields on the {@link LRUCache.SetOptions} options param will override
|
|
9942
|
+
* their corresponding values in the constructor options for the scope
|
|
9943
|
+
* of this single `set()` operation.
|
|
9944
|
+
*
|
|
9945
|
+
* If `start` is provided, then that will set the effective start
|
|
9946
|
+
* time for the TTL calculation. Note that this must be a previous
|
|
9947
|
+
* value of `performance.now()` if supported, or a previous value of
|
|
9948
|
+
* `Date.now()` if not.
|
|
9949
|
+
*
|
|
9950
|
+
* Options object may also include `size`, which will prevent
|
|
9951
|
+
* calling the `sizeCalculation` function and just use the specified
|
|
9952
|
+
* number if it is a positive integer, and `noDisposeOnSet` which
|
|
9953
|
+
* will prevent calling a `dispose` function in the case of
|
|
9954
|
+
* overwrites.
|
|
9955
|
+
*
|
|
9956
|
+
* If the `size` (or return value of `sizeCalculation`) for a given
|
|
9957
|
+
* entry is greater than `maxEntrySize`, then the item will not be
|
|
9958
|
+
* added to the cache.
|
|
9959
|
+
*
|
|
9960
|
+
* Will update the recency of the entry.
|
|
9961
|
+
*
|
|
9962
|
+
* If the value is `undefined`, then this is an alias for
|
|
9963
|
+
* `cache.delete(key)`. `undefined` is never stored in the cache.
|
|
9964
|
+
*/
|
|
9965
|
+
set(k, v, setOptions = {}) {
|
|
9966
|
+
if (v === void 0) {
|
|
9967
|
+
this.delete(k);
|
|
9968
|
+
return this;
|
|
9969
|
+
}
|
|
9970
|
+
const { ttl = this.ttl, start, noDisposeOnSet = this.noDisposeOnSet, sizeCalculation = this.sizeCalculation, status } = setOptions;
|
|
9971
|
+
let { noUpdateTTL = this.noUpdateTTL } = setOptions;
|
|
9972
|
+
const size = this.#requireSize(k, v, setOptions.size || 0, sizeCalculation);
|
|
9973
|
+
if (this.maxEntrySize && size > this.maxEntrySize) {
|
|
9974
|
+
if (status) {
|
|
9975
|
+
status.set = "miss";
|
|
9976
|
+
status.maxEntrySizeExceeded = true;
|
|
9977
|
+
}
|
|
9978
|
+
this.#delete(k, "set");
|
|
9979
|
+
return this;
|
|
9980
|
+
}
|
|
9981
|
+
let index = this.#size === 0 ? void 0 : this.#keyMap.get(k);
|
|
9982
|
+
if (index === void 0) {
|
|
9983
|
+
index = this.#size === 0 ? this.#tail : this.#free.length !== 0 ? this.#free.pop() : this.#size === this.#max ? this.#evict(false) : this.#size;
|
|
9984
|
+
this.#keyList[index] = k;
|
|
9985
|
+
this.#valList[index] = v;
|
|
9986
|
+
this.#keyMap.set(k, index);
|
|
9987
|
+
this.#next[this.#tail] = index;
|
|
9988
|
+
this.#prev[index] = this.#tail;
|
|
9989
|
+
this.#tail = index;
|
|
9990
|
+
this.#size++;
|
|
9991
|
+
this.#addItemSize(index, size, status);
|
|
9992
|
+
if (status) status.set = "add";
|
|
9993
|
+
noUpdateTTL = false;
|
|
9994
|
+
if (this.#hasOnInsert) this.#onInsert?.(v, k, "add");
|
|
9995
|
+
} else {
|
|
9996
|
+
this.#moveToTail(index);
|
|
9997
|
+
const oldVal = this.#valList[index];
|
|
9998
|
+
if (v !== oldVal) {
|
|
9999
|
+
if (this.#hasFetchMethod && this.#isBackgroundFetch(oldVal)) {
|
|
10000
|
+
oldVal.__abortController.abort(/* @__PURE__ */ new Error("replaced"));
|
|
10001
|
+
const { __staleWhileFetching: s } = oldVal;
|
|
10002
|
+
if (s !== void 0 && !noDisposeOnSet) {
|
|
10003
|
+
if (this.#hasDispose) this.#dispose?.(s, k, "set");
|
|
10004
|
+
if (this.#hasDisposeAfter) this.#disposed?.push([
|
|
10005
|
+
s,
|
|
10006
|
+
k,
|
|
10007
|
+
"set"
|
|
10008
|
+
]);
|
|
10009
|
+
}
|
|
10010
|
+
} else if (!noDisposeOnSet) {
|
|
10011
|
+
if (this.#hasDispose) this.#dispose?.(oldVal, k, "set");
|
|
10012
|
+
if (this.#hasDisposeAfter) this.#disposed?.push([
|
|
10013
|
+
oldVal,
|
|
10014
|
+
k,
|
|
10015
|
+
"set"
|
|
10016
|
+
]);
|
|
10017
|
+
}
|
|
10018
|
+
this.#removeItemSize(index);
|
|
10019
|
+
this.#addItemSize(index, size, status);
|
|
10020
|
+
this.#valList[index] = v;
|
|
10021
|
+
if (status) {
|
|
10022
|
+
status.set = "replace";
|
|
10023
|
+
const oldValue = oldVal && this.#isBackgroundFetch(oldVal) ? oldVal.__staleWhileFetching : oldVal;
|
|
10024
|
+
if (oldValue !== void 0) status.oldValue = oldValue;
|
|
10025
|
+
}
|
|
10026
|
+
} else if (status) status.set = "update";
|
|
10027
|
+
if (this.#hasOnInsert) this.onInsert?.(v, k, v === oldVal ? "update" : "replace");
|
|
10028
|
+
}
|
|
10029
|
+
if (ttl !== 0 && !this.#ttls) this.#initializeTTLTracking();
|
|
10030
|
+
if (this.#ttls) {
|
|
10031
|
+
if (!noUpdateTTL) this.#setItemTTL(index, ttl, start);
|
|
10032
|
+
if (status) this.#statusTTL(status, index);
|
|
10033
|
+
}
|
|
10034
|
+
if (!noDisposeOnSet && this.#hasDisposeAfter && this.#disposed) {
|
|
10035
|
+
const dt = this.#disposed;
|
|
10036
|
+
let task;
|
|
10037
|
+
while (task = dt?.shift()) this.#disposeAfter?.(...task);
|
|
10038
|
+
}
|
|
10039
|
+
return this;
|
|
10040
|
+
}
|
|
10041
|
+
/**
|
|
10042
|
+
* Evict the least recently used item, returning its value or
|
|
10043
|
+
* `undefined` if cache is empty.
|
|
10044
|
+
*/
|
|
10045
|
+
pop() {
|
|
10046
|
+
try {
|
|
10047
|
+
while (this.#size) {
|
|
10048
|
+
const val = this.#valList[this.#head];
|
|
10049
|
+
this.#evict(true);
|
|
10050
|
+
if (this.#isBackgroundFetch(val)) {
|
|
10051
|
+
if (val.__staleWhileFetching) return val.__staleWhileFetching;
|
|
10052
|
+
} else if (val !== void 0) return val;
|
|
10053
|
+
}
|
|
10054
|
+
} finally {
|
|
10055
|
+
if (this.#hasDisposeAfter && this.#disposed) {
|
|
10056
|
+
const dt = this.#disposed;
|
|
10057
|
+
let task;
|
|
10058
|
+
while (task = dt?.shift()) this.#disposeAfter?.(...task);
|
|
10059
|
+
}
|
|
10060
|
+
}
|
|
10061
|
+
}
|
|
10062
|
+
#evict(free) {
|
|
10063
|
+
const head = this.#head;
|
|
10064
|
+
const k = this.#keyList[head];
|
|
10065
|
+
const v = this.#valList[head];
|
|
10066
|
+
if (this.#hasFetchMethod && this.#isBackgroundFetch(v)) v.__abortController.abort(/* @__PURE__ */ new Error("evicted"));
|
|
10067
|
+
else if (this.#hasDispose || this.#hasDisposeAfter) {
|
|
10068
|
+
if (this.#hasDispose) this.#dispose?.(v, k, "evict");
|
|
10069
|
+
if (this.#hasDisposeAfter) this.#disposed?.push([
|
|
10070
|
+
v,
|
|
10071
|
+
k,
|
|
10072
|
+
"evict"
|
|
10073
|
+
]);
|
|
10074
|
+
}
|
|
10075
|
+
this.#removeItemSize(head);
|
|
10076
|
+
if (free) {
|
|
10077
|
+
this.#keyList[head] = void 0;
|
|
10078
|
+
this.#valList[head] = void 0;
|
|
10079
|
+
this.#free.push(head);
|
|
10080
|
+
}
|
|
10081
|
+
if (this.#size === 1) {
|
|
10082
|
+
this.#head = this.#tail = 0;
|
|
10083
|
+
this.#free.length = 0;
|
|
10084
|
+
} else this.#head = this.#next[head];
|
|
10085
|
+
this.#keyMap.delete(k);
|
|
10086
|
+
this.#size--;
|
|
10087
|
+
return head;
|
|
10088
|
+
}
|
|
10089
|
+
/**
|
|
10090
|
+
* Check if a key is in the cache, without updating the recency of use.
|
|
10091
|
+
* Will return false if the item is stale, even though it is technically
|
|
10092
|
+
* in the cache.
|
|
10093
|
+
*
|
|
10094
|
+
* Check if a key is in the cache, without updating the recency of
|
|
10095
|
+
* use. Age is updated if {@link LRUCache.OptionsBase.updateAgeOnHas} is set
|
|
10096
|
+
* to `true` in either the options or the constructor.
|
|
10097
|
+
*
|
|
10098
|
+
* Will return `false` if the item is stale, even though it is technically in
|
|
10099
|
+
* the cache. The difference can be determined (if it matters) by using a
|
|
10100
|
+
* `status` argument, and inspecting the `has` field.
|
|
10101
|
+
*
|
|
10102
|
+
* Will not update item age unless
|
|
10103
|
+
* {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
|
|
10104
|
+
*/
|
|
10105
|
+
has(k, hasOptions = {}) {
|
|
10106
|
+
const { updateAgeOnHas = this.updateAgeOnHas, status } = hasOptions;
|
|
10107
|
+
const index = this.#keyMap.get(k);
|
|
10108
|
+
if (index !== void 0) {
|
|
10109
|
+
const v = this.#valList[index];
|
|
10110
|
+
if (this.#isBackgroundFetch(v) && v.__staleWhileFetching === void 0) return false;
|
|
10111
|
+
if (!this.#isStale(index)) {
|
|
10112
|
+
if (updateAgeOnHas) this.#updateItemAge(index);
|
|
10113
|
+
if (status) {
|
|
10114
|
+
status.has = "hit";
|
|
10115
|
+
this.#statusTTL(status, index);
|
|
10116
|
+
}
|
|
10117
|
+
return true;
|
|
10118
|
+
} else if (status) {
|
|
10119
|
+
status.has = "stale";
|
|
10120
|
+
this.#statusTTL(status, index);
|
|
10121
|
+
}
|
|
10122
|
+
} else if (status) status.has = "miss";
|
|
10123
|
+
return false;
|
|
10124
|
+
}
|
|
10125
|
+
/**
|
|
10126
|
+
* Like {@link LRUCache#get} but doesn't update recency or delete stale
|
|
10127
|
+
* items.
|
|
10128
|
+
*
|
|
10129
|
+
* Returns `undefined` if the item is stale, unless
|
|
10130
|
+
* {@link LRUCache.OptionsBase.allowStale} is set.
|
|
10131
|
+
*/
|
|
10132
|
+
peek(k, peekOptions = {}) {
|
|
10133
|
+
const { allowStale = this.allowStale } = peekOptions;
|
|
10134
|
+
const index = this.#keyMap.get(k);
|
|
10135
|
+
if (index === void 0 || !allowStale && this.#isStale(index)) return;
|
|
10136
|
+
const v = this.#valList[index];
|
|
10137
|
+
return this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
10138
|
+
}
|
|
10139
|
+
#backgroundFetch(k, index, options, context) {
|
|
10140
|
+
const v = index === void 0 ? void 0 : this.#valList[index];
|
|
10141
|
+
if (this.#isBackgroundFetch(v)) return v;
|
|
10142
|
+
const ac = new AC();
|
|
10143
|
+
const { signal } = options;
|
|
10144
|
+
signal?.addEventListener("abort", () => ac.abort(signal.reason), { signal: ac.signal });
|
|
10145
|
+
const fetchOpts = {
|
|
10146
|
+
signal: ac.signal,
|
|
10147
|
+
options,
|
|
10148
|
+
context
|
|
10149
|
+
};
|
|
10150
|
+
const cb = (v, updateCache = false) => {
|
|
10151
|
+
const { aborted } = ac.signal;
|
|
10152
|
+
const ignoreAbort = options.ignoreFetchAbort && v !== void 0;
|
|
10153
|
+
if (options.status) if (aborted && !updateCache) {
|
|
10154
|
+
options.status.fetchAborted = true;
|
|
10155
|
+
options.status.fetchError = ac.signal.reason;
|
|
10156
|
+
if (ignoreAbort) options.status.fetchAbortIgnored = true;
|
|
10157
|
+
} else options.status.fetchResolved = true;
|
|
10158
|
+
if (aborted && !ignoreAbort && !updateCache) return fetchFail(ac.signal.reason);
|
|
10159
|
+
const bf = p;
|
|
10160
|
+
const vl = this.#valList[index];
|
|
10161
|
+
if (vl === p || ignoreAbort && updateCache && vl === void 0) if (v === void 0) if (bf.__staleWhileFetching !== void 0) this.#valList[index] = bf.__staleWhileFetching;
|
|
10162
|
+
else this.#delete(k, "fetch");
|
|
10163
|
+
else {
|
|
10164
|
+
if (options.status) options.status.fetchUpdated = true;
|
|
10165
|
+
this.set(k, v, fetchOpts.options);
|
|
10166
|
+
}
|
|
10167
|
+
return v;
|
|
10168
|
+
};
|
|
10169
|
+
const eb = (er) => {
|
|
10170
|
+
if (options.status) {
|
|
10171
|
+
options.status.fetchRejected = true;
|
|
10172
|
+
options.status.fetchError = er;
|
|
10173
|
+
}
|
|
10174
|
+
return fetchFail(er);
|
|
10175
|
+
};
|
|
10176
|
+
const fetchFail = (er) => {
|
|
10177
|
+
const { aborted } = ac.signal;
|
|
10178
|
+
const allowStaleAborted = aborted && options.allowStaleOnFetchAbort;
|
|
10179
|
+
const allowStale = allowStaleAborted || options.allowStaleOnFetchRejection;
|
|
10180
|
+
const noDelete = allowStale || options.noDeleteOnFetchRejection;
|
|
10181
|
+
const bf = p;
|
|
10182
|
+
if (this.#valList[index] === p) {
|
|
10183
|
+
if (!noDelete || bf.__staleWhileFetching === void 0) this.#delete(k, "fetch");
|
|
10184
|
+
else if (!allowStaleAborted) this.#valList[index] = bf.__staleWhileFetching;
|
|
10185
|
+
}
|
|
10186
|
+
if (allowStale) {
|
|
10187
|
+
if (options.status && bf.__staleWhileFetching !== void 0) options.status.returnedStale = true;
|
|
10188
|
+
return bf.__staleWhileFetching;
|
|
10189
|
+
} else if (bf.__returned === bf) throw er;
|
|
10190
|
+
};
|
|
10191
|
+
const pcall = (res, rej) => {
|
|
10192
|
+
const fmp = this.#fetchMethod?.(k, v, fetchOpts);
|
|
10193
|
+
if (fmp && fmp instanceof Promise) fmp.then((v) => res(v === void 0 ? void 0 : v), rej);
|
|
10194
|
+
ac.signal.addEventListener("abort", () => {
|
|
10195
|
+
if (!options.ignoreFetchAbort || options.allowStaleOnFetchAbort) {
|
|
10196
|
+
res(void 0);
|
|
10197
|
+
if (options.allowStaleOnFetchAbort) res = (v) => cb(v, true);
|
|
10198
|
+
}
|
|
10199
|
+
});
|
|
10200
|
+
};
|
|
10201
|
+
if (options.status) options.status.fetchDispatched = true;
|
|
10202
|
+
const p = new Promise(pcall).then(cb, eb);
|
|
10203
|
+
const bf = Object.assign(p, {
|
|
10204
|
+
__abortController: ac,
|
|
10205
|
+
__staleWhileFetching: v,
|
|
10206
|
+
__returned: void 0
|
|
10207
|
+
});
|
|
10208
|
+
if (index === void 0) {
|
|
10209
|
+
this.set(k, bf, {
|
|
10210
|
+
...fetchOpts.options,
|
|
10211
|
+
status: void 0
|
|
10212
|
+
});
|
|
10213
|
+
index = this.#keyMap.get(k);
|
|
10214
|
+
} else this.#valList[index] = bf;
|
|
10215
|
+
return bf;
|
|
10216
|
+
}
|
|
10217
|
+
#isBackgroundFetch(p) {
|
|
10218
|
+
if (!this.#hasFetchMethod) return false;
|
|
10219
|
+
const b = p;
|
|
10220
|
+
return !!b && b instanceof Promise && b.hasOwnProperty("__staleWhileFetching") && b.__abortController instanceof AC;
|
|
10221
|
+
}
|
|
10222
|
+
async fetch(k, fetchOptions = {}) {
|
|
10223
|
+
const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, ttl = this.ttl, noDisposeOnSet = this.noDisposeOnSet, size = 0, sizeCalculation = this.sizeCalculation, noUpdateTTL = this.noUpdateTTL, noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection = this.allowStaleOnFetchRejection, ignoreFetchAbort = this.ignoreFetchAbort, allowStaleOnFetchAbort = this.allowStaleOnFetchAbort, context, forceRefresh = false, status, signal } = fetchOptions;
|
|
10224
|
+
if (!this.#hasFetchMethod) {
|
|
10225
|
+
if (status) status.fetch = "get";
|
|
10226
|
+
return this.get(k, {
|
|
10227
|
+
allowStale,
|
|
10228
|
+
updateAgeOnGet,
|
|
10229
|
+
noDeleteOnStaleGet,
|
|
10230
|
+
status
|
|
10231
|
+
});
|
|
10232
|
+
}
|
|
10233
|
+
const options = {
|
|
10234
|
+
allowStale,
|
|
10235
|
+
updateAgeOnGet,
|
|
10236
|
+
noDeleteOnStaleGet,
|
|
10237
|
+
ttl,
|
|
10238
|
+
noDisposeOnSet,
|
|
10239
|
+
size,
|
|
10240
|
+
sizeCalculation,
|
|
10241
|
+
noUpdateTTL,
|
|
10242
|
+
noDeleteOnFetchRejection,
|
|
10243
|
+
allowStaleOnFetchRejection,
|
|
10244
|
+
allowStaleOnFetchAbort,
|
|
10245
|
+
ignoreFetchAbort,
|
|
10246
|
+
status,
|
|
10247
|
+
signal
|
|
10248
|
+
};
|
|
10249
|
+
let index = this.#keyMap.get(k);
|
|
10250
|
+
if (index === void 0) {
|
|
10251
|
+
if (status) status.fetch = "miss";
|
|
10252
|
+
const p = this.#backgroundFetch(k, index, options, context);
|
|
10253
|
+
return p.__returned = p;
|
|
10254
|
+
} else {
|
|
10255
|
+
const v = this.#valList[index];
|
|
10256
|
+
if (this.#isBackgroundFetch(v)) {
|
|
10257
|
+
const stale = allowStale && v.__staleWhileFetching !== void 0;
|
|
10258
|
+
if (status) {
|
|
10259
|
+
status.fetch = "inflight";
|
|
10260
|
+
if (stale) status.returnedStale = true;
|
|
10261
|
+
}
|
|
10262
|
+
return stale ? v.__staleWhileFetching : v.__returned = v;
|
|
10263
|
+
}
|
|
10264
|
+
const isStale = this.#isStale(index);
|
|
10265
|
+
if (!forceRefresh && !isStale) {
|
|
10266
|
+
if (status) status.fetch = "hit";
|
|
10267
|
+
this.#moveToTail(index);
|
|
10268
|
+
if (updateAgeOnGet) this.#updateItemAge(index);
|
|
10269
|
+
if (status) this.#statusTTL(status, index);
|
|
10270
|
+
return v;
|
|
10271
|
+
}
|
|
10272
|
+
const p = this.#backgroundFetch(k, index, options, context);
|
|
10273
|
+
const staleVal = p.__staleWhileFetching !== void 0 && allowStale;
|
|
10274
|
+
if (status) {
|
|
10275
|
+
status.fetch = isStale ? "stale" : "refresh";
|
|
10276
|
+
if (staleVal && isStale) status.returnedStale = true;
|
|
10277
|
+
}
|
|
10278
|
+
return staleVal ? p.__staleWhileFetching : p.__returned = p;
|
|
10279
|
+
}
|
|
10280
|
+
}
|
|
10281
|
+
async forceFetch(k, fetchOptions = {}) {
|
|
10282
|
+
const v = await this.fetch(k, fetchOptions);
|
|
10283
|
+
if (v === void 0) throw new Error("fetch() returned undefined");
|
|
10284
|
+
return v;
|
|
10285
|
+
}
|
|
10286
|
+
memo(k, memoOptions = {}) {
|
|
10287
|
+
const memoMethod = this.#memoMethod;
|
|
10288
|
+
if (!memoMethod) throw new Error("no memoMethod provided to constructor");
|
|
10289
|
+
const { context, forceRefresh, ...options } = memoOptions;
|
|
10290
|
+
const v = this.get(k, options);
|
|
10291
|
+
if (!forceRefresh && v !== void 0) return v;
|
|
10292
|
+
const vv = memoMethod(k, v, {
|
|
10293
|
+
options,
|
|
10294
|
+
context
|
|
10295
|
+
});
|
|
10296
|
+
this.set(k, vv, options);
|
|
10297
|
+
return vv;
|
|
10298
|
+
}
|
|
10299
|
+
/**
|
|
10300
|
+
* Return a value from the cache. Will update the recency of the cache
|
|
10301
|
+
* entry found.
|
|
10302
|
+
*
|
|
10303
|
+
* If the key is not found, get() will return `undefined`.
|
|
10304
|
+
*/
|
|
10305
|
+
get(k, getOptions = {}) {
|
|
10306
|
+
const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, status } = getOptions;
|
|
10307
|
+
const index = this.#keyMap.get(k);
|
|
10308
|
+
if (index !== void 0) {
|
|
10309
|
+
const value = this.#valList[index];
|
|
10310
|
+
const fetching = this.#isBackgroundFetch(value);
|
|
10311
|
+
if (status) this.#statusTTL(status, index);
|
|
10312
|
+
if (this.#isStale(index)) {
|
|
10313
|
+
if (status) status.get = "stale";
|
|
10314
|
+
if (!fetching) {
|
|
10315
|
+
if (!noDeleteOnStaleGet) this.#delete(k, "expire");
|
|
10316
|
+
if (status && allowStale) status.returnedStale = true;
|
|
10317
|
+
return allowStale ? value : void 0;
|
|
10318
|
+
} else {
|
|
10319
|
+
if (status && allowStale && value.__staleWhileFetching !== void 0) status.returnedStale = true;
|
|
10320
|
+
return allowStale ? value.__staleWhileFetching : void 0;
|
|
10321
|
+
}
|
|
10322
|
+
} else {
|
|
10323
|
+
if (status) status.get = "hit";
|
|
10324
|
+
if (fetching) return value.__staleWhileFetching;
|
|
10325
|
+
this.#moveToTail(index);
|
|
10326
|
+
if (updateAgeOnGet) this.#updateItemAge(index);
|
|
10327
|
+
return value;
|
|
10328
|
+
}
|
|
10329
|
+
} else if (status) status.get = "miss";
|
|
10330
|
+
}
|
|
10331
|
+
#connect(p, n) {
|
|
10332
|
+
this.#prev[n] = p;
|
|
10333
|
+
this.#next[p] = n;
|
|
10334
|
+
}
|
|
10335
|
+
#moveToTail(index) {
|
|
10336
|
+
if (index !== this.#tail) {
|
|
10337
|
+
if (index === this.#head) this.#head = this.#next[index];
|
|
10338
|
+
else this.#connect(this.#prev[index], this.#next[index]);
|
|
10339
|
+
this.#connect(this.#tail, index);
|
|
10340
|
+
this.#tail = index;
|
|
10341
|
+
}
|
|
10342
|
+
}
|
|
10343
|
+
/**
|
|
10344
|
+
* Deletes a key out of the cache.
|
|
10345
|
+
*
|
|
10346
|
+
* Returns true if the key was deleted, false otherwise.
|
|
10347
|
+
*/
|
|
10348
|
+
delete(k) {
|
|
10349
|
+
return this.#delete(k, "delete");
|
|
10350
|
+
}
|
|
10351
|
+
#delete(k, reason) {
|
|
10352
|
+
let deleted = false;
|
|
10353
|
+
if (this.#size !== 0) {
|
|
10354
|
+
const index = this.#keyMap.get(k);
|
|
10355
|
+
if (index !== void 0) {
|
|
10356
|
+
deleted = true;
|
|
10357
|
+
if (this.#size === 1) this.#clear(reason);
|
|
10358
|
+
else {
|
|
10359
|
+
this.#removeItemSize(index);
|
|
10360
|
+
const v = this.#valList[index];
|
|
10361
|
+
if (this.#isBackgroundFetch(v)) v.__abortController.abort(/* @__PURE__ */ new Error("deleted"));
|
|
10362
|
+
else if (this.#hasDispose || this.#hasDisposeAfter) {
|
|
10363
|
+
if (this.#hasDispose) this.#dispose?.(v, k, reason);
|
|
10364
|
+
if (this.#hasDisposeAfter) this.#disposed?.push([
|
|
10365
|
+
v,
|
|
10366
|
+
k,
|
|
10367
|
+
reason
|
|
10368
|
+
]);
|
|
10369
|
+
}
|
|
10370
|
+
this.#keyMap.delete(k);
|
|
10371
|
+
this.#keyList[index] = void 0;
|
|
10372
|
+
this.#valList[index] = void 0;
|
|
10373
|
+
if (index === this.#tail) this.#tail = this.#prev[index];
|
|
10374
|
+
else if (index === this.#head) this.#head = this.#next[index];
|
|
10375
|
+
else {
|
|
10376
|
+
const pi = this.#prev[index];
|
|
10377
|
+
this.#next[pi] = this.#next[index];
|
|
10378
|
+
const ni = this.#next[index];
|
|
10379
|
+
this.#prev[ni] = this.#prev[index];
|
|
10380
|
+
}
|
|
10381
|
+
this.#size--;
|
|
10382
|
+
this.#free.push(index);
|
|
10383
|
+
}
|
|
10384
|
+
}
|
|
10385
|
+
}
|
|
10386
|
+
if (this.#hasDisposeAfter && this.#disposed?.length) {
|
|
10387
|
+
const dt = this.#disposed;
|
|
10388
|
+
let task;
|
|
10389
|
+
while (task = dt?.shift()) this.#disposeAfter?.(...task);
|
|
10390
|
+
}
|
|
10391
|
+
return deleted;
|
|
10392
|
+
}
|
|
10393
|
+
/**
|
|
10394
|
+
* Clear the cache entirely, throwing away all values.
|
|
10395
|
+
*/
|
|
10396
|
+
clear() {
|
|
10397
|
+
return this.#clear("delete");
|
|
10398
|
+
}
|
|
10399
|
+
#clear(reason) {
|
|
10400
|
+
for (const index of this.#rindexes({ allowStale: true })) {
|
|
10401
|
+
const v = this.#valList[index];
|
|
10402
|
+
if (this.#isBackgroundFetch(v)) v.__abortController.abort(/* @__PURE__ */ new Error("deleted"));
|
|
10403
|
+
else {
|
|
10404
|
+
const k = this.#keyList[index];
|
|
10405
|
+
if (this.#hasDispose) this.#dispose?.(v, k, reason);
|
|
10406
|
+
if (this.#hasDisposeAfter) this.#disposed?.push([
|
|
10407
|
+
v,
|
|
10408
|
+
k,
|
|
10409
|
+
reason
|
|
10410
|
+
]);
|
|
10411
|
+
}
|
|
10412
|
+
}
|
|
10413
|
+
this.#keyMap.clear();
|
|
10414
|
+
this.#valList.fill(void 0);
|
|
10415
|
+
this.#keyList.fill(void 0);
|
|
10416
|
+
if (this.#ttls && this.#starts) {
|
|
10417
|
+
this.#ttls.fill(0);
|
|
10418
|
+
this.#starts.fill(0);
|
|
10419
|
+
}
|
|
10420
|
+
if (this.#sizes) this.#sizes.fill(0);
|
|
10421
|
+
this.#head = 0;
|
|
10422
|
+
this.#tail = 0;
|
|
10423
|
+
this.#free.length = 0;
|
|
10424
|
+
this.#calculatedSize = 0;
|
|
10425
|
+
this.#size = 0;
|
|
10426
|
+
if (this.#hasDisposeAfter && this.#disposed) {
|
|
10427
|
+
const dt = this.#disposed;
|
|
10428
|
+
let task;
|
|
10429
|
+
while (task = dt?.shift()) this.#disposeAfter?.(...task);
|
|
10430
|
+
}
|
|
10431
|
+
}
|
|
10432
|
+
};
|
|
10433
|
+
//#endregion
|
|
10434
|
+
//#region ../../../../sdk/model/dist/columns/column_providers/providers.js
|
|
10435
|
+
/**
|
|
10436
|
+
* Unified memoised factory dispatching to the right provider flavour by the
|
|
10437
|
+
* source shape:
|
|
10438
|
+
* - `TreeNodeAccessor` → {@link AccessorColumnsProvider}
|
|
10439
|
+
* (indexed by `root.handle`, walks the accessor tree once per root).
|
|
10440
|
+
* - `UpstreamBlockCtx<AccessorHandle>[]` (or omitted — pulled from the
|
|
10441
|
+
* ambient ctx) → {@link ResultPoolColumnsProvider}
|
|
10442
|
+
* (indexed by a content-hash of the block list).
|
|
10443
|
+
*
|
|
10444
|
+
* Both branches return cached instances within their LRU window, so repeated
|
|
10445
|
+
* calls with the same source skip re-walking / re-hashing.
|
|
10446
|
+
*/
|
|
10447
|
+
function ColumnsProvider(source) {
|
|
10448
|
+
if (isNil(source) || Array.isArray(source)) return ResultPoolColumnsProvider(source);
|
|
10449
|
+
else if (source instanceof TreeNodeAccessor) return AccessorColumnsProvider(source);
|
|
10450
|
+
else throw new Error("Unknown columns provider source");
|
|
10451
|
+
}
|
|
10452
|
+
/**
|
|
10453
|
+
* Memoised constructor — same `root.handle` returns the same
|
|
10454
|
+
* {@link AccessorColumnsProviderImpl}, so `indexAccessorRoot` runs once per
|
|
10455
|
+
* accessor root (within the LRU window).
|
|
10456
|
+
*/
|
|
10457
|
+
const _accessorProviderCache = new LRUCache({ max: 64 });
|
|
10458
|
+
function AccessorColumnsProvider(root) {
|
|
10459
|
+
let provider = _accessorProviderCache.get(root.handle);
|
|
10460
|
+
if (provider === void 0) {
|
|
10461
|
+
provider = new AccessorColumnsProviderImpl(root);
|
|
10462
|
+
_accessorProviderCache.set(root.handle, provider);
|
|
10463
|
+
}
|
|
10464
|
+
return provider;
|
|
10465
|
+
}
|
|
10466
|
+
/**
|
|
10467
|
+
* Memoised constructor — same `rawPool` content returns the same
|
|
10468
|
+
* {@link ResultPoolColumnsProviderImpl}, so `indexPoolBlock` runs once per
|
|
10469
|
+
* pool snapshot (within the LRU window).
|
|
10470
|
+
*/
|
|
10471
|
+
const _resultPoolProviderCache = new LRUCache({ max: 4 });
|
|
10472
|
+
function ResultPoolColumnsProvider(rawPool = getCfgRenderCtx().getUpstreamBlockCtx()) {
|
|
10473
|
+
const key = hashRawPool(rawPool);
|
|
10474
|
+
let provider = _resultPoolProviderCache.get(key);
|
|
10475
|
+
if (provider === void 0) {
|
|
10476
|
+
provider = new ResultPoolColumnsProviderImpl(rawPool);
|
|
10477
|
+
_resultPoolProviderCache.set(key, provider);
|
|
10478
|
+
}
|
|
10479
|
+
return provider;
|
|
10480
|
+
}
|
|
10481
|
+
/**
|
|
10482
|
+
* Sandbox-specific provider over a {@link TreeNodeAccessor} root. Uses the
|
|
10483
|
+
* accessor's own `resolvePath` as the canonical root path for id construction,
|
|
10484
|
+
* and adds `getColumns()` returning {@link ColumnLazy}s on top of the generic
|
|
10485
|
+
* entries index.
|
|
10486
|
+
*/
|
|
10487
|
+
var AccessorColumnsProviderImpl = class extends AccessorEntriesProvider {
|
|
10488
|
+
cachedColumns;
|
|
10489
|
+
constructor(root) {
|
|
10490
|
+
super(root, root.resolvePath);
|
|
10491
|
+
}
|
|
10492
|
+
getColumns() {
|
|
10493
|
+
if (this.cachedColumns !== void 0) return this.cachedColumns;
|
|
10494
|
+
return this.cachedColumns = Array.from(this.entries.values()).map((e) => ColumnLazyImpl.fromAccessor(e)).filter((v) => !isNil(v));
|
|
10495
|
+
}
|
|
10496
|
+
};
|
|
10497
|
+
/**
|
|
10498
|
+
* Sandbox-specific result-pool provider. Accepts the raw handle-shaped blocks
|
|
10499
|
+
* returned by {@link GlobalCfgRenderCtxMethods.getUpstreamBlockCtx} and
|
|
10500
|
+
* wraps them into {@link TreeNodeAccessor}s, then adds `getColumns()`.
|
|
10501
|
+
*/
|
|
10502
|
+
var ResultPoolColumnsProviderImpl = class extends ResultPoolEntriesProvider {
|
|
10503
|
+
cachedColumns;
|
|
10504
|
+
constructor(rawPool = getCfgRenderCtx().getUpstreamBlockCtx()) {
|
|
10505
|
+
const blocks = rawPool.map((b) => ({
|
|
10506
|
+
blockId: b.blockId,
|
|
10507
|
+
prodCtx: b.prodCtx !== void 0 ? new TreeNodeAccessor(b.prodCtx, [b.blockId, "prodCtx"]) : void 0,
|
|
10508
|
+
stagingCtx: b.stagingCtx !== void 0 ? new TreeNodeAccessor(b.stagingCtx, [b.blockId, "stagingCtx"]) : void 0,
|
|
10509
|
+
prodIncomplete: b.prodIncomplete,
|
|
10510
|
+
stagingIncomplete: b.stagingIncomplete
|
|
10511
|
+
}));
|
|
10512
|
+
super(blocks);
|
|
10513
|
+
}
|
|
10514
|
+
getColumns() {
|
|
10515
|
+
if (this.cachedColumns !== void 0) return this.cachedColumns;
|
|
10516
|
+
return this.cachedColumns = Array.from(this.getPObjectEntries().values()).map((e) => ColumnLazyImpl.fromAccessor(e)).filter((v) => !isNil(v));
|
|
10517
|
+
}
|
|
10518
|
+
};
|
|
10519
|
+
function hashRawPool(rawPool) {
|
|
10520
|
+
return rawPool.map((b) => `${b.blockId}\x1f${b.prodCtx ?? ""}\x1f${b.stagingCtx ?? ""}\x1f${b.prodIncomplete ? 1 : 0}\x1f${b.stagingIncomplete ? 1 : 0}`).join("");
|
|
10521
|
+
}
|
|
10522
|
+
//#endregion
|
|
10523
|
+
//#region ../../../../sdk/model/dist/columns/column_providers/index.js
|
|
10524
|
+
/**
|
|
10525
|
+
* Build the default set of ColumnsProviders for the ambient render ctx:
|
|
10526
|
+
* - `AccessorColumnsProvider` over `outputs` (if present)
|
|
10527
|
+
* - `AccessorColumnsProvider` over `prerun` (if present)
|
|
10528
|
+
* - `ResultPoolColumnsProvider` over `rawResultPool`
|
|
10529
|
+
*
|
|
10530
|
+
* Pulls handles directly from the ambient `cfgRenderCtx`. Returns `[]` when
|
|
10531
|
+
* called outside a render context.
|
|
10532
|
+
*
|
|
10533
|
+
* Result is memoised per-ctx (WeakMap → array). Repeated calls within the
|
|
10534
|
+
* same render cycle return the same provider triplet — inner providers are
|
|
10535
|
+
* also LRU-memoised by their content keys, so even a cache miss here doesn't
|
|
10536
|
+
* re-walk the trees.
|
|
10537
|
+
*/
|
|
10538
|
+
const _ctxProvidersCache = /* @__PURE__ */ new WeakMap();
|
|
10539
|
+
function getCtxProviders(deps) {
|
|
10540
|
+
const ctx = deps?.ctx ?? getCfgRenderCtx();
|
|
10541
|
+
const cached = _ctxProvidersCache.get(ctx);
|
|
10542
|
+
if (cached !== void 0) return cached;
|
|
10543
|
+
const providers = [];
|
|
10544
|
+
const outputs = ctx.getAccessorHandleByName(MainAccessorName);
|
|
10545
|
+
if (outputs !== void 0) providers.push(ColumnsProvider(new TreeNodeAccessor(outputs, [MainAccessorName])));
|
|
10546
|
+
const prerun = ctx.getAccessorHandleByName(StagingAccessorName);
|
|
10547
|
+
if (prerun !== void 0) providers.push(ColumnsProvider(new TreeNodeAccessor(prerun, [StagingAccessorName])));
|
|
10548
|
+
providers.push(ColumnsProvider(ctx.getUpstreamBlockCtx()));
|
|
10549
|
+
_ctxProvidersCache.set(ctx, providers);
|
|
10550
|
+
return providers;
|
|
10551
|
+
}
|
|
10552
|
+
//#endregion
|
|
10553
|
+
//#region ../../../../sdk/model/dist/columns/column_lazy.js
|
|
10554
|
+
/**
|
|
10555
|
+
* Thrown by leaf-recipe factories when the requested column is provably
|
|
10556
|
+
* absent in the active render ctx — i.e. every relevant accessor reports
|
|
10557
|
+
* `inputsLocked` and the column did not appear. Distinct from the
|
|
10558
|
+
* `undefined` return that the factories still use for the "resolving" case
|
|
10559
|
+
* (the column may still appear later).
|
|
10560
|
+
*
|
|
10561
|
+
* Catch at the boundary (resolver / filter+sort wiring / data-table assembly)
|
|
10562
|
+
* when partial absence should be surfaced to the user rather than silently
|
|
10563
|
+
* producing an empty result.
|
|
10564
|
+
*/
|
|
10565
|
+
var ColumnAbsentError = class extends Error {
|
|
10566
|
+
id;
|
|
10567
|
+
constructor(id) {
|
|
10568
|
+
super(`Column is absent in the active render ctx and will not appear: ${id}`);
|
|
10569
|
+
this.id = id;
|
|
10570
|
+
this.name = "ColumnAbsentError";
|
|
10571
|
+
}
|
|
10572
|
+
};
|
|
10573
|
+
/**
|
|
10574
|
+
* ColumnLazy is the leaf-recipe building block: a {@link ColumnRecipe} whose
|
|
10575
|
+
* `id` is a bare {@link PObjectId} and whose readers are bound to a single
|
|
10576
|
+
* tree-accessor leaf. Layered encodings (Overridden / Discovered / Filtered)
|
|
10577
|
+
* are reified through their dedicated recipe classes and reference leaf
|
|
10578
|
+
* columns by id.
|
|
10579
|
+
*/
|
|
10580
|
+
var ColumnLazyImpl = class ColumnLazyImpl {
|
|
10581
|
+
id;
|
|
10582
|
+
options;
|
|
10583
|
+
specCache;
|
|
10584
|
+
dataCache;
|
|
10585
|
+
dataStatusCache;
|
|
10586
|
+
constructor(id, options) {
|
|
10587
|
+
this.id = id;
|
|
10588
|
+
this.options = options;
|
|
10589
|
+
}
|
|
10590
|
+
/** A leaf-recipe references exactly one column — its own id. */
|
|
10591
|
+
getReferencedIds() {
|
|
10592
|
+
return [this.id];
|
|
10593
|
+
}
|
|
10594
|
+
getSpec() {
|
|
10595
|
+
if (this.specCache === void 0) this.specCache = { value: this.options.getSpec() };
|
|
10596
|
+
return this.specCache.value;
|
|
10597
|
+
}
|
|
10598
|
+
/** Leaf-shaped — points straight at `this.id`. */
|
|
10599
|
+
getQuery() {
|
|
10600
|
+
return {
|
|
10601
|
+
type: "column",
|
|
10602
|
+
column: this.id
|
|
10603
|
+
};
|
|
10604
|
+
}
|
|
10605
|
+
/** Leaf-only: not on the recipe interface — only the leaf can read data directly. */
|
|
10606
|
+
getData() {
|
|
10607
|
+
if (this.dataCache === void 0) this.dataCache = { value: this.options.getData() };
|
|
10608
|
+
return this.dataCache.value;
|
|
10609
|
+
}
|
|
10610
|
+
getDataStatus() {
|
|
10611
|
+
if (this.dataStatusCache === void 0) this.dataStatusCache = { value: this.options.getDataStatus() };
|
|
10612
|
+
return this.dataStatusCache.value;
|
|
10613
|
+
}
|
|
10614
|
+
/**
|
|
10615
|
+
* Overlay overrides → produces a {@link ColumnOverriddenRecipe} wrapping
|
|
10616
|
+
* this leaf. ColumnLazy itself stays bare (id remains a plain PObjectId);
|
|
10617
|
+
* layering lives entirely in the recipe wrappers.
|
|
10618
|
+
*/
|
|
10619
|
+
withSpecs(overrides) {
|
|
10620
|
+
return ColumnOverriddenRecipe.wrap(this, overrides);
|
|
10621
|
+
}
|
|
10622
|
+
/**
|
|
10623
|
+
* Resolve via the ambient {@link ColumnRegistry}. Spec is resolved eagerly:
|
|
10624
|
+
* returns `undefined` if the leaf isn't reachable yet (resolving). Throws
|
|
10625
|
+
* {@link ColumnAbsentError} when every relevant accessor is `inputsLocked`
|
|
10626
|
+
* and the column did not appear — the column will not exist in this ctx.
|
|
10627
|
+
* Data and dataStatus stay lazy.
|
|
10628
|
+
*/
|
|
10629
|
+
static fromId(id, { ctx } = {}) {
|
|
10630
|
+
const registry = new ColumnRegistry(getCtxProviders({ ctx }));
|
|
10631
|
+
const leaf = registry.resolve(id);
|
|
10632
|
+
if (isNil(leaf)) {
|
|
10633
|
+
if (registry.isFinal()) throw new ColumnAbsentError(id);
|
|
10634
|
+
return;
|
|
10635
|
+
}
|
|
10636
|
+
const spec = readSpecAccessor(leaf);
|
|
10637
|
+
if (isNil(spec)) {
|
|
10638
|
+
if (leaf.accessor.getInputsLocked()) throw new ColumnAbsentError(id);
|
|
10639
|
+
return;
|
|
10640
|
+
}
|
|
10641
|
+
if (!spec.hasData()) return void 0;
|
|
10642
|
+
return new ColumnLazyImpl(id, {
|
|
10643
|
+
getSpec: () => spec.getDataAsJson(),
|
|
10644
|
+
getData: () => readDataAccessor(leaf),
|
|
10645
|
+
getDataStatus: () => readDataStatus(leaf)
|
|
10646
|
+
});
|
|
10647
|
+
}
|
|
10648
|
+
/** {@link PlRef} wrapper over {@link fromId}. */
|
|
10649
|
+
static fromPlRef(ref) {
|
|
10650
|
+
return ColumnLazyImpl.fromId(createGlobalPObjectId(ref.blockId, ref.name));
|
|
10651
|
+
}
|
|
10652
|
+
/**
|
|
10653
|
+
* Bind directly to an accessor-backed {@link LeafEntry} — no registry.
|
|
10654
|
+
* Throws {@link ColumnAbsentError} if the leaf has no spec field and its
|
|
10655
|
+
* accessor is `inputsLocked`. Returns `undefined` while still resolving.
|
|
10656
|
+
*/
|
|
10657
|
+
static fromAccessor(entry) {
|
|
10658
|
+
const spec = readSpecAccessor(entry);
|
|
10659
|
+
if (isNil(spec)) {
|
|
10660
|
+
if (entry.accessor.getInputsLocked()) throw new ColumnAbsentError(entry.id);
|
|
10661
|
+
return;
|
|
10662
|
+
}
|
|
10663
|
+
if (!spec.hasData()) return void 0;
|
|
10664
|
+
return new ColumnLazyImpl(entry.id, {
|
|
10665
|
+
getSpec: () => spec.getDataAsJson(),
|
|
10666
|
+
getData: () => readDataAccessor(entry),
|
|
10667
|
+
getDataStatus: () => readDataStatus(entry)
|
|
10668
|
+
});
|
|
10669
|
+
}
|
|
10670
|
+
/**
|
|
10671
|
+
* Wrap a materialised {@link PColumn}. If the input is already a
|
|
10672
|
+
* {@link ColumnLazy} it is returned as-is.
|
|
10673
|
+
*/
|
|
10674
|
+
static fromColumn(column) {
|
|
10675
|
+
if (column instanceof ColumnLazyImpl) return column;
|
|
10676
|
+
return new ColumnLazyImpl(column.id, {
|
|
10677
|
+
getSpec: () => column.spec,
|
|
10678
|
+
getData: () => column.data,
|
|
10679
|
+
getDataStatus: () => "present"
|
|
10680
|
+
});
|
|
10681
|
+
}
|
|
10682
|
+
/**
|
|
10683
|
+
* Distinguishes `present` / `resolving` / `absent` for a {@link PObjectId}
|
|
10684
|
+
* in the active render ctx. Falls back to the registry's `isFinal()`
|
|
10685
|
+
* when the id has no entry — only then we can say `absent` instead of
|
|
10686
|
+
* `resolving`.
|
|
10687
|
+
*/
|
|
10688
|
+
static getStatusById(id, { ctx } = {}) {
|
|
10689
|
+
const registry = new ColumnRegistry(getCtxProviders({ ctx }));
|
|
10690
|
+
const leaf = registry.resolve(id);
|
|
10691
|
+
if (isNil(leaf)) return registry.isFinal() ? "absent" : "resolving";
|
|
10692
|
+
return getLeafEntryStatus(leaf);
|
|
10693
|
+
}
|
|
10694
|
+
/** {@link PlRef} wrapper over {@link getStatusById}. */
|
|
10695
|
+
static getStatusByPlRef(ref, opts = {}) {
|
|
10696
|
+
return ColumnLazyImpl.getStatusById(createGlobalPObjectId(ref.blockId, ref.name), opts);
|
|
10697
|
+
}
|
|
10698
|
+
/** No registry — reads straight off the entry's accessor. */
|
|
10699
|
+
static getStatusByAccessor(entry) {
|
|
10700
|
+
return getLeafEntryStatus(entry);
|
|
10701
|
+
}
|
|
10702
|
+
};
|
|
10703
|
+
/**
|
|
10704
|
+
* Unified dispatcher — picks the right `ColumnLazyImpl.fromX` by source
|
|
10705
|
+
* shape. For ambiguous inputs callers can still use the explicit factories
|
|
10706
|
+
* (also attached as properties: `ColumnLazy.fromId`, `.fromPlRef`,
|
|
10707
|
+
* `.fromAccessor`, `.fromColumn`).
|
|
10708
|
+
*/
|
|
10709
|
+
function ColumnLazyDispatch(source, opts = {}) {
|
|
10710
|
+
if (typeof source === "string") return ColumnLazyImpl.fromId(source, opts);
|
|
10711
|
+
if (source instanceof ColumnLazyImpl) return source;
|
|
10712
|
+
if ("accessor" in source) return ColumnLazyImpl.fromAccessor(source);
|
|
10713
|
+
if (isPlRef(source)) return ColumnLazyImpl.fromPlRef(source);
|
|
10714
|
+
if (isPColumn(source)) return ColumnLazyImpl.fromColumn(source);
|
|
10715
|
+
throw new Error("ColumnLazy: unknown source shape");
|
|
10716
|
+
}
|
|
10717
|
+
/**
|
|
10718
|
+
* Polymorphic counterpart to {@link ColumnLazyDispatch}: returns the
|
|
10719
|
+
* {@link ColumnResolutionStatus} for any factory input without constructing
|
|
10720
|
+
* the recipe. For already-materialised sources ({@link PColumn} value,
|
|
10721
|
+
* existing {@link ColumnLazy}) status is `present` by construction.
|
|
10722
|
+
*/
|
|
10723
|
+
function ColumnLazyGetStatus(source, opts = {}) {
|
|
10724
|
+
if (typeof source === "string") return ColumnLazyImpl.getStatusById(source, opts);
|
|
10725
|
+
if (source instanceof ColumnLazyImpl) return "present";
|
|
10726
|
+
if ("accessor" in source) return ColumnLazyImpl.getStatusByAccessor(source);
|
|
10727
|
+
if (isPlRef(source)) return ColumnLazyImpl.getStatusByPlRef(source, opts);
|
|
10728
|
+
if (isPColumn(source)) return "present";
|
|
10729
|
+
throw new Error("ColumnLazy.getStatus: unknown source shape");
|
|
10730
|
+
}
|
|
10731
|
+
const ColumnLazy = Object.assign(ColumnLazyDispatch, {
|
|
10732
|
+
fromId: ColumnLazyImpl.fromId,
|
|
10733
|
+
fromPlRef: ColumnLazyImpl.fromPlRef,
|
|
10734
|
+
fromAccessor: ColumnLazyImpl.fromAccessor,
|
|
10735
|
+
fromColumn: ColumnLazyImpl.fromColumn,
|
|
10736
|
+
getStatus: ColumnLazyGetStatus,
|
|
10737
|
+
getStatusById: ColumnLazyImpl.getStatusById,
|
|
10738
|
+
getStatusByPlRef: ColumnLazyImpl.getStatusByPlRef,
|
|
10739
|
+
getStatusByAccessor: ColumnLazyImpl.getStatusByAccessor
|
|
10740
|
+
});
|
|
10741
|
+
const readSpecAccessor = memoizeByEntry(({ accessor, name }) => accessor.traverse({
|
|
10742
|
+
field: `${name}.spec`,
|
|
10743
|
+
assertFieldType: "Input",
|
|
10744
|
+
ignoreError: true
|
|
10745
|
+
}));
|
|
10746
|
+
/**
|
|
10747
|
+
* Per-entry counterpart to {@link readDataStatus}: tells whether the leaf's
|
|
10748
|
+
* **spec** can be read in this ctx, and — for the negative cases —
|
|
10749
|
+
* distinguishes `resolving` from `absent` via `getInputsLocked()`.
|
|
10750
|
+
*
|
|
10751
|
+
* - spec field not yet on the entry's accessor + inputs locked → `absent`
|
|
10752
|
+
* - spec field not yet on the entry's accessor + still resolving → `resolving`
|
|
10753
|
+
* - spec resource present but bytes not yet written → `resolving`
|
|
10754
|
+
* (transient — the spec resource is connected, just unfilled)
|
|
10755
|
+
* - spec resource present and `hasData()` → `present`
|
|
10756
|
+
*/
|
|
10757
|
+
function getLeafEntryStatus(entry) {
|
|
10758
|
+
const spec = readSpecAccessor(entry);
|
|
10759
|
+
if (isNil(spec)) return entry.accessor.getInputsLocked() ? "absent" : "resolving";
|
|
10760
|
+
if (!spec.hasData()) return "resolving";
|
|
10761
|
+
return "present";
|
|
10762
|
+
}
|
|
10763
|
+
const readDataAccessor = memoizeByEntry(({ accessor, name }) => accessor.traverse({
|
|
10764
|
+
field: `${name}.data`,
|
|
10765
|
+
assertFieldType: "Input",
|
|
10766
|
+
ignoreError: true
|
|
10767
|
+
}));
|
|
10768
|
+
const readDataStatus = memoizeByEntry(({ accessor, name }) => {
|
|
10769
|
+
if (accessor.listInputFields().includes(`${name}.data`)) return "present";
|
|
10770
|
+
return accessor.getInputsLocked() ? "absent" : "resolving";
|
|
10771
|
+
});
|
|
10772
|
+
function memoizeByEntry(fn) {
|
|
10773
|
+
const cache = new LRUCache({ max: 1e3 });
|
|
10774
|
+
return (entry) => {
|
|
10775
|
+
const key = `${entry.accessor.handle}:${entry.name}`;
|
|
10776
|
+
let hit = cache.get(key);
|
|
10777
|
+
if (!hit) cache.set(key, hit = { value: fn(entry) });
|
|
10778
|
+
return hit.value;
|
|
10779
|
+
};
|
|
10780
|
+
}
|
|
10781
|
+
//#endregion
|
|
10782
|
+
//#region ../../../../sdk/model/dist/columns/column_recipes/index.js
|
|
10783
|
+
/**
|
|
10784
|
+
* Build a `ColumnRecipe` from a stringified id. Dispatches to the matching
|
|
10785
|
+
* concrete recipe variant based on the id's encoding and recurses on
|
|
10786
|
+
* wrappers' inner `source`:
|
|
10787
|
+
*
|
|
10788
|
+
* - bare {@link PObjectId} (non-JSON) → `ColumnLazy.fromId`
|
|
10789
|
+
* - `ColumnDiscoveredKey` → {@link ColumnDiscoveredRecipe}
|
|
10790
|
+
* - `ColumnOverriddenKey { source, specOverrides }` → recurse on `source`,
|
|
10791
|
+
* then {@link ColumnOverriddenRecipe.wrap}
|
|
10792
|
+
* - `ColumnFilteredKey { source, axisFilters }` → recurse on `source`,
|
|
10793
|
+
* then {@link ColumnFilteredRecipe.wrap}
|
|
10794
|
+
*
|
|
10795
|
+
* Returns `undefined` for unsupported variants (e.g. AnchoredPColumnId,
|
|
10796
|
+
* which needs an anchor map to resolve) or when a nested source itself
|
|
10797
|
+
* cannot be built.
|
|
10798
|
+
*/
|
|
10799
|
+
function ColumnRecipeBuild(id, opts = {}) {
|
|
10800
|
+
const parsed = parseColumnIdSafely(id);
|
|
10801
|
+
if (isPObjectKey(parsed)) return ColumnLazyImpl.fromId(id, opts);
|
|
10802
|
+
if (isColumnDiscoveredKey(parsed)) return ColumnDiscoveredRecipe.fromKey(parsed, opts);
|
|
10803
|
+
if (isColumnOverriddenKey(parsed)) {
|
|
10804
|
+
const inner = ColumnRecipe(parsed.source, opts);
|
|
10805
|
+
if (inner === void 0) return void 0;
|
|
10806
|
+
return ColumnOverriddenRecipe.wrap(inner, parsed.specOverrides);
|
|
10807
|
+
}
|
|
10808
|
+
if (isColumnFilteredKey(parsed)) {
|
|
10809
|
+
if (typeof parsed.source !== "string") throw new Error(`Unsupported ColumnRecipe id variant: filtered column with non-string source (${JSON.stringify(parsed.source)})`);
|
|
10810
|
+
const inner = ColumnRecipe(parsed.source, opts);
|
|
10811
|
+
if (inner === void 0) return void 0;
|
|
10812
|
+
return ColumnFilteredRecipe.wrap(inner, parsed.axisFilters);
|
|
10813
|
+
}
|
|
10814
|
+
throw new Error(`Unsupported ColumnRecipe id variant: ${id}`);
|
|
10815
|
+
}
|
|
10816
|
+
/**
|
|
10817
|
+
* Resolution status counterpart to {@link ColumnRecipeBuild}. Dispatches on
|
|
10818
|
+
* the parsed id shape to the matching `getStatusBy*` static — never
|
|
10819
|
+
* constructs the recipe. Use this at boundaries (resolver, filter/sort
|
|
10820
|
+
* targets) to throw early on `absent` instead of silently producing an empty
|
|
10821
|
+
* recipe via {@link ColumnRecipeBuild}.
|
|
10822
|
+
*/
|
|
10823
|
+
function ColumnRecipeGetStatus(id, opts = {}) {
|
|
10824
|
+
const parsed = parseColumnIdSafely(id);
|
|
10825
|
+
if (isPObjectKey(parsed)) return ColumnLazyImpl.getStatusById(id, opts);
|
|
10826
|
+
if (isColumnDiscoveredKey(parsed)) return ColumnDiscoveredRecipe.getStatusByKey(parsed, opts);
|
|
10827
|
+
if (isColumnOverriddenKey(parsed)) return ColumnOverriddenRecipe.getStatusByKey(parsed, opts);
|
|
10828
|
+
if (isColumnFilteredKey(parsed)) return ColumnFilteredRecipe.getStatusByKey(parsed, opts);
|
|
10829
|
+
throw new Error(`Unsupported ColumnRecipe id variant: ${id}`);
|
|
10830
|
+
}
|
|
10831
|
+
const ColumnRecipe = Object.assign(ColumnRecipeBuild, { getStatus: ColumnRecipeGetStatus });
|
|
10832
|
+
//#endregion
|
|
10833
|
+
//#region ../../../../sdk/model/dist/columns/column.js
|
|
10834
|
+
/**
|
|
10835
|
+
* Unified entry point — routes between the two top-level dispatchers:
|
|
10836
|
+
* - string id (`PObjectId` / `ColumnUniversalId`) → {@link ColumnRecipe}
|
|
10837
|
+
* - object source (`PlRef` / `LeafEntry` / `PColumn` / `ColumnLazy`) → {@link ColumnLazy}
|
|
10838
|
+
*
|
|
10839
|
+
* `ColumnLazy` is itself a `ColumnRecipe<PObjectId>`, so the return type is
|
|
10840
|
+
* the common `ColumnRecipe`.
|
|
10841
|
+
*/
|
|
10842
|
+
function Column(source, opts) {
|
|
10843
|
+
if (typeof source === "string") return ColumnRecipe(source, opts);
|
|
10844
|
+
return ColumnLazy(source, opts);
|
|
10845
|
+
}
|
|
10846
|
+
//#endregion
|
|
10847
|
+
//#region ../../../../sdk/model/dist/columns/utils.js
|
|
10848
|
+
/**
|
|
10849
|
+
* Hit-side axis qualifications for the recipe — the ones that should land on
|
|
10850
|
+
* the outer-join entry wrapping this column at the consumer boundary.
|
|
10851
|
+
*
|
|
10852
|
+
* Descends {@link ColumnOverriddenRecipe} / {@link ColumnFilteredRecipe} via
|
|
10853
|
+
* `getInner()` until it finds a {@link ColumnDiscoveredRecipe}; otherwise
|
|
10854
|
+
* returns `[]`. Pure recipe walk — no query-tree introspection.
|
|
10855
|
+
*/
|
|
10856
|
+
function hitQualifications(recipe) {
|
|
10857
|
+
return findDiscovered(recipe)?.getColumnQualifications() ?? [];
|
|
10858
|
+
}
|
|
10859
|
+
/**
|
|
10860
|
+
* Per-primary-column axis qualifications for the recipe — applied to the
|
|
10861
|
+
* outer primary anchors on this recipe's group side. Keyed by the external
|
|
10862
|
+
* primary column id (NOT by columns inside this recipe's own query).
|
|
10863
|
+
*
|
|
10864
|
+
* Same walk strategy as {@link hitQualifications}.
|
|
10865
|
+
*/
|
|
10866
|
+
function queriesQualifications(recipe) {
|
|
10867
|
+
return findDiscovered(recipe)?.getQueriesQualifications() ?? {};
|
|
10868
|
+
}
|
|
10869
|
+
/**
|
|
10870
|
+
* Walk wrapper layers (Overridden, Filtered) until a {@link
|
|
10871
|
+
* ColumnDiscoveredRecipe} is found. Returns `undefined` if the recipe chain
|
|
10872
|
+
* has no Discovered layer (bare leaves and Overridden-over-leaf cases).
|
|
10873
|
+
*
|
|
10874
|
+
* Invariant from the wrapper classes themselves: there is at most one
|
|
10875
|
+
* Discovered layer in any recipe chain — Discovered is constructed only via
|
|
10876
|
+
* its own factory and is never re-wrapped by Discovered.
|
|
10877
|
+
*/
|
|
10878
|
+
function findDiscovered(recipe) {
|
|
10879
|
+
let current = recipe;
|
|
10880
|
+
while (true) {
|
|
10881
|
+
if (current instanceof ColumnDiscoveredRecipe) return current;
|
|
10882
|
+
if (current instanceof ColumnOverriddenRecipe || current instanceof ColumnFilteredRecipe) {
|
|
10883
|
+
current = current.getInner();
|
|
10884
|
+
continue;
|
|
10885
|
+
}
|
|
10886
|
+
return;
|
|
10887
|
+
}
|
|
10888
|
+
}
|
|
10889
|
+
//#endregion
|
|
10890
|
+
//#region ../../../../sdk/model/dist/filters/traverse.js
|
|
10891
|
+
/**
|
|
10892
|
+
* Recursively traverses a FilterSpec tree bottom-up, applying visitor callbacks.
|
|
10893
|
+
*
|
|
10894
|
+
* Entries with `{ type: undefined }` inside `and`/`or` arrays are skipped
|
|
10895
|
+
* (these represent unfilled filter slots in the UI).
|
|
10896
|
+
*
|
|
10897
|
+
* Traversal order:
|
|
10898
|
+
* 1. Recurse into child filters (`and`/`or`/`not`)
|
|
10899
|
+
* 2. Apply the corresponding visitor callback with already-traversed children
|
|
10900
|
+
* 3. For leaf nodes, call `leaf` directly
|
|
10901
|
+
*/
|
|
10902
|
+
function traverseFilterSpec(filter, visitor) {
|
|
10903
|
+
return traverseFilterSpecImpl(filter, visitor);
|
|
10904
|
+
}
|
|
10905
|
+
/** Internal implementation with simple generics for clean recursion. */
|
|
10906
|
+
function traverseFilterSpecImpl(filter, visitor) {
|
|
10907
|
+
switch (filter.type) {
|
|
10908
|
+
case "and": return visitor.and(filter.filters.filter((f) => f.type !== void 0).map((f) => traverseFilterSpecImpl(f, visitor)));
|
|
10909
|
+
case "or": return visitor.or(filter.filters.filter((f) => f.type !== void 0).map((f) => traverseFilterSpecImpl(f, visitor)));
|
|
10910
|
+
case "not": return visitor.not(traverseFilterSpecImpl(filter.filter, visitor));
|
|
10911
|
+
default: return visitor.leaf(filter);
|
|
10912
|
+
}
|
|
10913
|
+
}
|
|
10914
|
+
/** Collects all column references (`column` and `rhs` fields) from filter leaves. */
|
|
10915
|
+
function collectFilterSpecColumns(filter) {
|
|
10916
|
+
return traverseFilterSpec(filter, {
|
|
10917
|
+
leaf: (leaf) => {
|
|
10918
|
+
const cols = [];
|
|
10919
|
+
if ("column" in leaf && leaf.column !== void 0) cols.push(leaf.column);
|
|
10920
|
+
if ("rhs" in leaf && leaf.rhs !== void 0) cols.push(leaf.rhs);
|
|
10921
|
+
return cols;
|
|
10922
|
+
},
|
|
10923
|
+
and: (results) => results.flat(),
|
|
10924
|
+
or: (results) => results.flat(),
|
|
10925
|
+
not: (result) => result
|
|
10926
|
+
});
|
|
10927
|
+
}
|
|
10928
|
+
//#endregion
|
|
10929
|
+
//#region ../../../../sdk/model/dist/filters/converters/filterToQuery.js
|
|
10930
|
+
/** Converts a QueryColumnId object into a SpecQueryExpression reference. */
|
|
10931
|
+
function resolveColumnRef(col) {
|
|
10932
|
+
return col.type === "axis" ? {
|
|
10933
|
+
type: "axisRef",
|
|
10934
|
+
value: col.id
|
|
10935
|
+
} : {
|
|
10936
|
+
type: "columnRef",
|
|
10937
|
+
value: col.id
|
|
10938
|
+
};
|
|
10939
|
+
}
|
|
10940
|
+
/** Converts a FilterSpec tree into a SpecQueryExpression. */
|
|
10941
|
+
function filterSpecToSpecQueryExpr(filter) {
|
|
10942
|
+
return traverseFilterSpec(filter, {
|
|
10943
|
+
leaf: leafToSpecQueryExpr,
|
|
10944
|
+
and: (inputs) => {
|
|
10945
|
+
if (inputs.length === 0) throw new Error("AND filter requires at least one operand");
|
|
10946
|
+
return {
|
|
10947
|
+
type: "and",
|
|
10948
|
+
input: inputs
|
|
10949
|
+
};
|
|
10950
|
+
},
|
|
10951
|
+
or: (inputs) => {
|
|
10952
|
+
if (inputs.length === 0) throw new Error("OR filter requires at least one operand");
|
|
10953
|
+
return {
|
|
10954
|
+
type: "or",
|
|
10955
|
+
input: inputs
|
|
10956
|
+
};
|
|
10957
|
+
},
|
|
10958
|
+
not: (input) => ({
|
|
10959
|
+
type: "not",
|
|
10960
|
+
input
|
|
10961
|
+
})
|
|
8213
10962
|
});
|
|
8214
10963
|
}
|
|
8215
10964
|
function leafToSpecQueryExpr(filter) {
|
|
@@ -8621,12 +11370,13 @@ function upgradePlDataTableStateV2(state) {
|
|
|
8621
11370
|
...entry,
|
|
8622
11371
|
filtersState: []
|
|
8623
11372
|
})),
|
|
8624
|
-
pTableParams:
|
|
11373
|
+
pTableParams: createDefaultPTableParamsV7()
|
|
8625
11374
|
};
|
|
8626
11375
|
if (state.version === 3) state = createPlDataTableStateV2();
|
|
8627
11376
|
if (state.version === 4) state = migrateV4toV6(state);
|
|
8628
11377
|
if (state.version === 5) state = migrateV5toV6(state);
|
|
8629
11378
|
if (state.version === 6) state = migrateV6toV7(state);
|
|
11379
|
+
if (state.version === 7) state = migrateV7toV8(state);
|
|
8630
11380
|
return state;
|
|
8631
11381
|
}
|
|
8632
11382
|
/** Migrate v5 to v6: unwrap `{source, labeled}` colIds in gridState. */
|
|
@@ -8637,7 +11387,7 @@ function migrateV5toV6(state) {
|
|
|
8637
11387
|
...entry,
|
|
8638
11388
|
gridState: unwrapV5GridState(entry.gridState)
|
|
8639
11389
|
})),
|
|
8640
|
-
pTableParams:
|
|
11390
|
+
pTableParams: createDefaultPTableParamsV7()
|
|
8641
11391
|
};
|
|
8642
11392
|
}
|
|
8643
11393
|
/** Convert v5 wrapped colId JSON to bare PTableColumnSpec JSON, taking `.source`.
|
|
@@ -8694,10 +11444,7 @@ function migrateV4toV6(state) {
|
|
|
8694
11444
|
const nextId = () => ++idCounter;
|
|
8695
11445
|
const migratedCache = state.stateCache.map((entry) => {
|
|
8696
11446
|
const leaves = [];
|
|
8697
|
-
for (const f of entry.filtersState) if (f.filter !== null && !f.filter.disabled)
|
|
8698
|
-
const column = canonicalizeJson(f.id);
|
|
8699
|
-
leaves.push(migrateTableFilter(column, f.filter.value, nextId));
|
|
8700
|
-
}
|
|
11447
|
+
for (const f of entry.filtersState) if (f.filter !== null && !f.filter.disabled) leaves.push(migrateTableFilter(canonicalizeJson(f.id), f.filter.value, nextId));
|
|
8701
11448
|
const filtersState = leaves.length > 0 ? {
|
|
8702
11449
|
id: nextId(),
|
|
8703
11450
|
type: "and",
|
|
@@ -8725,10 +11472,11 @@ function migrateV4toV6(state) {
|
|
|
8725
11472
|
filters: distillFilterSpec(currentCache.filtersState),
|
|
8726
11473
|
defaultFilters: null,
|
|
8727
11474
|
sorting: state.pTableParams.sorting
|
|
8728
|
-
} :
|
|
11475
|
+
} : createDefaultPTableParamsV7()
|
|
8729
11476
|
};
|
|
8730
11477
|
}
|
|
8731
|
-
/** Migrate a single per-column PlTableFilter to a
|
|
11478
|
+
/** Migrate a single per-column PlTableFilter to a v7-form tree node (legacy
|
|
11479
|
+
* string column ids). v7 → v8 later converts these to object form. */
|
|
8732
11480
|
function migrateTableFilter(column, filter, nextId) {
|
|
8733
11481
|
const id = nextId();
|
|
8734
11482
|
switch (filter.type) {
|
|
@@ -8854,7 +11602,9 @@ function migrateTableFilter(column, filter, nextId) {
|
|
|
8854
11602
|
};
|
|
8855
11603
|
}
|
|
8856
11604
|
}
|
|
8857
|
-
|
|
11605
|
+
/** Default pTableParams in the v7 shape (sorting: []). Used by intermediate
|
|
11606
|
+
* migration steps that produce v6/v7 state before the v7 → v8 conversion. */
|
|
11607
|
+
function createDefaultPTableParamsV7() {
|
|
8858
11608
|
return {
|
|
8859
11609
|
sourceId: null,
|
|
8860
11610
|
hiddenColIds: null,
|
|
@@ -8863,13 +11613,109 @@ function createDefaultPTableParams() {
|
|
|
8863
11613
|
sorting: []
|
|
8864
11614
|
};
|
|
8865
11615
|
}
|
|
11616
|
+
function createDefaultPTableParams() {
|
|
11617
|
+
return {
|
|
11618
|
+
sourceId: null,
|
|
11619
|
+
hiddenColIds: null,
|
|
11620
|
+
filters: null,
|
|
11621
|
+
defaultFilters: null,
|
|
11622
|
+
sorting: null
|
|
11623
|
+
};
|
|
11624
|
+
}
|
|
8866
11625
|
function createPlDataTableStateV2() {
|
|
8867
11626
|
return {
|
|
8868
|
-
version:
|
|
11627
|
+
version: 8,
|
|
8869
11628
|
stateCache: [],
|
|
8870
11629
|
pTableParams: createDefaultPTableParams()
|
|
8871
11630
|
};
|
|
8872
11631
|
}
|
|
11632
|
+
function migrateV7toV8(state) {
|
|
11633
|
+
const newCache = state.stateCache.map((entry) => ({
|
|
11634
|
+
sourceId: entry.sourceId,
|
|
11635
|
+
gridState: entry.gridState,
|
|
11636
|
+
sheetsState: entry.sheetsState,
|
|
11637
|
+
filtersState: convertFiltersWithMeta(entry.filtersState),
|
|
11638
|
+
defaultFiltersState: convertFiltersWithMeta(entry.defaultFiltersState),
|
|
11639
|
+
searchString: entry.searchString
|
|
11640
|
+
}));
|
|
11641
|
+
const params = state.pTableParams;
|
|
11642
|
+
let pTableParams;
|
|
11643
|
+
if (params.sourceId === null) pTableParams = createDefaultPTableParams();
|
|
11644
|
+
else pTableParams = {
|
|
11645
|
+
sourceId: params.sourceId,
|
|
11646
|
+
hiddenColIds: params.hiddenColIds,
|
|
11647
|
+
sorting: params.sorting.length === 0 ? null : params.sorting,
|
|
11648
|
+
filters: convertFiltersPlain(params.filters),
|
|
11649
|
+
defaultFilters: convertFiltersPlain(params.defaultFilters)
|
|
11650
|
+
};
|
|
11651
|
+
return {
|
|
11652
|
+
version: 8,
|
|
11653
|
+
stateCache: newCache,
|
|
11654
|
+
pTableParams
|
|
11655
|
+
};
|
|
11656
|
+
}
|
|
11657
|
+
function convertFiltersWithMeta(node) {
|
|
11658
|
+
if (node === null) return null;
|
|
11659
|
+
const result = pruneFilterNode(node);
|
|
11660
|
+
if (result === void 0) return null;
|
|
11661
|
+
return result;
|
|
11662
|
+
}
|
|
11663
|
+
function convertFiltersPlain(node) {
|
|
11664
|
+
if (node === null) return null;
|
|
11665
|
+
const result = pruneFilterNode(node);
|
|
11666
|
+
if (result === void 0) return null;
|
|
11667
|
+
return result;
|
|
11668
|
+
}
|
|
11669
|
+
/** Recursively converts and prunes a legacy v7 filter tree. Preserves meta
|
|
11670
|
+
* fields (id/isExpanded/source/isSuppressed) on non-leaf nodes. Returns
|
|
11671
|
+
* `undefined` when the subtree is empty after pruning. */
|
|
11672
|
+
function pruneFilterNode(node) {
|
|
11673
|
+
if (!node || typeof node !== "object") return void 0;
|
|
11674
|
+
const n = node;
|
|
11675
|
+
if (n.type === "and" || n.type === "or") {
|
|
11676
|
+
const kept = (n.filters ?? []).map((f) => pruneFilterNode(f)).filter((f) => f !== void 0);
|
|
11677
|
+
if (kept.length === 0) return void 0;
|
|
11678
|
+
return {
|
|
11679
|
+
...n,
|
|
11680
|
+
type: n.type,
|
|
11681
|
+
filters: kept
|
|
11682
|
+
};
|
|
11683
|
+
}
|
|
11684
|
+
if (n.type === "not") {
|
|
11685
|
+
const inner = pruneFilterNode(n.filter);
|
|
11686
|
+
if (inner === void 0) return void 0;
|
|
11687
|
+
return {
|
|
11688
|
+
...n,
|
|
11689
|
+
type: "not",
|
|
11690
|
+
filter: inner
|
|
11691
|
+
};
|
|
11692
|
+
}
|
|
11693
|
+
return convertLegacyLeaf(n);
|
|
11694
|
+
}
|
|
11695
|
+
function convertLegacyLeaf(leaf) {
|
|
11696
|
+
if (leaf.type === void 0) return leaf;
|
|
11697
|
+
const result = { ...leaf };
|
|
11698
|
+
if ("column" in result) {
|
|
11699
|
+
const c = parseLegacyLeafColumn(result.column);
|
|
11700
|
+
if (c === void 0) return void 0;
|
|
11701
|
+
result.column = c;
|
|
11702
|
+
}
|
|
11703
|
+
if ("rhs" in result) {
|
|
11704
|
+
const c = parseLegacyLeafColumn(result.rhs);
|
|
11705
|
+
if (c === void 0) return void 0;
|
|
11706
|
+
result.rhs = c;
|
|
11707
|
+
}
|
|
11708
|
+
return result;
|
|
11709
|
+
}
|
|
11710
|
+
function parseLegacyLeafColumn(s) {
|
|
11711
|
+
if (typeof s !== "string") return void 0;
|
|
11712
|
+
const parsed = parseJsonSafely(s);
|
|
11713
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
11714
|
+
if (!("type" in parsed) || !("id" in parsed)) return void 0;
|
|
11715
|
+
const t = parsed.type;
|
|
11716
|
+
if (t !== "axis" && t !== "column") return void 0;
|
|
11717
|
+
return parsed;
|
|
11718
|
+
}
|
|
8873
11719
|
//#endregion
|
|
8874
11720
|
//#region ../../../../sdk/model/dist/components/PlDataTable/createPlDataTable/utils.js
|
|
8875
11721
|
/** Check if column is hidden by default */
|
|
@@ -8932,18 +11778,29 @@ function getMatchingLabelColumns(columns, allLabelColumns) {
|
|
|
8932
11778
|
}
|
|
8933
11779
|
//#endregion
|
|
8934
11780
|
//#region ../../../../sdk/model/dist/components/PlDataTable/createPlDataTable/createPTableDefV3.js
|
|
11781
|
+
/**
|
|
11782
|
+
* Assemble a ptable def directly from recipes. Each secondary recipe is its own
|
|
11783
|
+
* outer-joined subtree: `getQuery()` encodes its linker chain, and its
|
|
11784
|
+
* hit-/queries-qualifications are derived on the spot via {@link hitQualifications}
|
|
11785
|
+
* / {@link queriesQualifications} — no pre-extracted DTO. Bare leaves yield empty
|
|
11786
|
+
* qualifications, so plain {@link ColumnRecipe} arrays (e.g. label columns) work
|
|
11787
|
+
* unchanged.
|
|
11788
|
+
*/
|
|
8935
11789
|
function createPTableDefV3(params) {
|
|
8936
11790
|
let query = {
|
|
8937
11791
|
type: params.primaryJoinType === "inner" ? "innerJoin" : "fullJoin",
|
|
8938
|
-
entries: params.primary.map((
|
|
11792
|
+
entries: params.primary.map((c) => columnToJoinEntry(c, []))
|
|
8939
11793
|
};
|
|
8940
11794
|
if (params.secondary.length > 0) query = {
|
|
8941
11795
|
type: "outerJoin",
|
|
8942
11796
|
primary: {
|
|
8943
11797
|
entry: query,
|
|
8944
|
-
qualifications: params.secondary.flatMap((
|
|
11798
|
+
qualifications: params.secondary.flatMap((s) => {
|
|
11799
|
+
const quals = queriesQualifications(s);
|
|
11800
|
+
return params.primary.flatMap((p) => quals[p.id] ?? []);
|
|
11801
|
+
})
|
|
8945
11802
|
},
|
|
8946
|
-
secondary: params.secondary.
|
|
11803
|
+
secondary: params.secondary.map((c) => columnToJoinEntry(c, hitQualifications(c)))
|
|
8947
11804
|
};
|
|
8948
11805
|
if (!isNil(params.filters)) {
|
|
8949
11806
|
const nonEmpty = distillFilterSpec(params.filters);
|
|
@@ -8963,7 +11820,7 @@ function createPTableDefV3(params) {
|
|
|
8963
11820
|
sortBy: params.sorting.map((s) => ({
|
|
8964
11821
|
expression: columnIdToExpr(s.column),
|
|
8965
11822
|
ascending: s.ascending,
|
|
8966
|
-
nullsFirst:
|
|
11823
|
+
nullsFirst: s.naAndAbsentAreLeastValues
|
|
8967
11824
|
}))
|
|
8968
11825
|
};
|
|
8969
11826
|
return { query };
|
|
@@ -8977,28 +11834,10 @@ function columnIdToExpr(col) {
|
|
|
8977
11834
|
value: col.id
|
|
8978
11835
|
};
|
|
8979
11836
|
}
|
|
8980
|
-
function
|
|
8981
|
-
return {
|
|
8982
|
-
entry: {
|
|
8983
|
-
type: "column",
|
|
8984
|
-
column: col
|
|
8985
|
-
},
|
|
8986
|
-
qualifications: qs
|
|
8987
|
-
};
|
|
8988
|
-
}
|
|
8989
|
-
function toJoinEntry(e) {
|
|
8990
|
-
const qs = e.qualifications ?? [];
|
|
8991
|
-
if (isNil(e.linkers) || e.linkers.length === 0) return toLeaf(e.column, qs);
|
|
11837
|
+
function columnToJoinEntry(col, qualifications) {
|
|
8992
11838
|
return {
|
|
8993
|
-
|
|
8994
|
-
|
|
8995
|
-
type: "linkerJoin",
|
|
8996
|
-
linker: { column: linker },
|
|
8997
|
-
secondary: [inner]
|
|
8998
|
-
},
|
|
8999
|
-
qualifications: []
|
|
9000
|
-
}), toLeaf(e.column, [])),
|
|
9001
|
-
qualifications: qs
|
|
11839
|
+
entry: col.getQuery(),
|
|
11840
|
+
qualifications
|
|
9002
11841
|
};
|
|
9003
11842
|
}
|
|
9004
11843
|
//#endregion
|
|
@@ -9013,14 +11852,38 @@ function createPTableDefV2(params) {
|
|
|
9013
11852
|
}
|
|
9014
11853
|
secondaryColumns.push(...params.labelColumns);
|
|
9015
11854
|
return createPTableDefV3({
|
|
9016
|
-
primary: coreColumns.map((column) => (
|
|
9017
|
-
secondary: secondaryColumns.map((column) => (
|
|
11855
|
+
primary: coreColumns.map((column) => ColumnLazyImpl.fromColumn(column)),
|
|
11856
|
+
secondary: secondaryColumns.map((column) => ColumnLazyImpl.fromColumn(column)),
|
|
9018
11857
|
primaryJoinType: params.coreJoinType,
|
|
9019
11858
|
filters: params.filters,
|
|
9020
11859
|
sorting: params.sorting
|
|
9021
11860
|
});
|
|
9022
11861
|
}
|
|
9023
11862
|
//#endregion
|
|
11863
|
+
//#region ../../../../sdk/model/dist/components/PlDataTable/columnResolver.js
|
|
11864
|
+
function createColumnResolver(columns, deps) {
|
|
11865
|
+
const axisIds = [];
|
|
11866
|
+
for (const c of columns) for (const ax of c.getSpec().axesSpec) axisIds.push(getAxisId(ax));
|
|
11867
|
+
const byFullId = /* @__PURE__ */ new Map();
|
|
11868
|
+
const byPObjectId = /* @__PURE__ */ new Map();
|
|
11869
|
+
for (const c of columns) {
|
|
11870
|
+
byFullId.set(c.id, c);
|
|
11871
|
+
const pid = extractPObjectId(c.id);
|
|
11872
|
+
const existing = byPObjectId.get(pid);
|
|
11873
|
+
if (existing === void 0) byPObjectId.set(pid, c);
|
|
11874
|
+
else if (existing.id !== c.id) deps?.warn?.(`Ambiguous PObjectId ${pid}: recipe ids ${existing.id} and ${c.id} both match — keeping first.`);
|
|
11875
|
+
}
|
|
11876
|
+
return (ref) => {
|
|
11877
|
+
if (ref.type === "axis") return axisIds.some((a) => matchAxisId(ref.id, a)) ? ref : void 0;
|
|
11878
|
+
const hit = byFullId.get(ref.id) ?? byPObjectId.get(extractPObjectId(ref.id));
|
|
11879
|
+
if (hit === void 0) return void 0;
|
|
11880
|
+
return {
|
|
11881
|
+
type: "column",
|
|
11882
|
+
id: hit.id
|
|
11883
|
+
};
|
|
11884
|
+
};
|
|
11885
|
+
}
|
|
11886
|
+
//#endregion
|
|
9024
11887
|
//#region ../../../../sdk/model/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js
|
|
9025
11888
|
/**
|
|
9026
11889
|
* Create p-table spec and handle given ui table state
|
|
@@ -9049,31 +11912,19 @@ function createPlDataTableV2(ctx, columns, tableState, options) {
|
|
|
9049
11912
|
};
|
|
9050
11913
|
});
|
|
9051
11914
|
const fullColumns = [...columns, ...fullLabelColumns];
|
|
9052
|
-
const
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
id: c.id
|
|
9058
|
-
}))];
|
|
9059
|
-
const fullColumnsIdsSet = new Set(fullColumnsIds.map((c) => canonicalizeJson(c)));
|
|
9060
|
-
const isValidColumnId = (id) => fullColumnsIdsSet.has(id);
|
|
9061
|
-
const filters = tableStateNormalized.pTableParams.filters;
|
|
9062
|
-
const defaultFilters = options?.filters ?? void 0;
|
|
9063
|
-
const firstInvalidFilterColumn = (filters !== null ? collectFilterSpecColumns(filters) : []).find((col) => !isValidColumnId(col));
|
|
9064
|
-
if (firstInvalidFilterColumn) throw new Error(`Invalid filter column ${firstInvalidFilterColumn}: column reference does not match the table columns`);
|
|
9065
|
-
const firstInvalidDefaultFilterColumn = (defaultFilters !== void 0 ? collectFilterSpecColumns(defaultFilters) : []).find((col) => !isValidColumnId(col));
|
|
9066
|
-
if (firstInvalidDefaultFilterColumn) throw new Error(`Invalid default filter column ${firstInvalidDefaultFilterColumn}: column reference does not match the table columns`);
|
|
11915
|
+
const resolver = createColumnResolver(fullColumns.map((c) => ColumnLazyImpl.fromColumn(c)), { warn: ctx.logWarn.bind(ctx) });
|
|
11916
|
+
const rawFilters = tableStateNormalized.pTableParams.filters;
|
|
11917
|
+
const rawDefaultFilters = options?.filters ?? void 0;
|
|
11918
|
+
const filters = remapFiltersThrowing(rawFilters, resolver, "filter");
|
|
11919
|
+
const defaultFilters = remapFiltersThrowing(rawDefaultFilters ?? null, resolver, "default filter");
|
|
9067
11920
|
const userSorting = tableStateNormalized.pTableParams.sorting;
|
|
9068
|
-
const sorting = (
|
|
9069
|
-
const firstInvalidSortingColumn = sorting.find((s) => !isValidColumnId(canonicalizeJson(s.column)));
|
|
9070
|
-
if (firstInvalidSortingColumn) throw new Error(`Invalid sorting column ${JSON.stringify(firstInvalidSortingColumn.column)}: column reference does not match the table columns`);
|
|
11921
|
+
const sorting = remapSortingThrowing((isNil$1(userSorting) ? options?.sorting : userSorting) ?? [], resolver);
|
|
9071
11922
|
const coreJoinType = options?.coreJoinType ?? "full";
|
|
9072
11923
|
const fullDef = createPTableDefV2({
|
|
9073
11924
|
columns,
|
|
9074
11925
|
labelColumns: fullLabelColumns,
|
|
9075
11926
|
coreJoinType,
|
|
9076
|
-
filters,
|
|
11927
|
+
filters: filters ?? null,
|
|
9077
11928
|
sorting,
|
|
9078
11929
|
coreColumnPredicate: options?.coreColumnPredicate
|
|
9079
11930
|
});
|
|
@@ -9090,10 +11941,7 @@ function createPlDataTableV2(ctx, columns, tableState, options) {
|
|
|
9090
11941
|
const coreColumnPredicate = options?.coreColumnPredicate;
|
|
9091
11942
|
if (coreColumnPredicate) columns.flatMap((c) => coreColumnPredicate(getColumnIdAndSpec(c)) ? [c.id] : []).forEach((c) => hiddenColumns.delete(c));
|
|
9092
11943
|
sorting.map((s) => s.column).filter((c) => c.type === "column").forEach((c) => hiddenColumns.delete(c.id));
|
|
9093
|
-
if (filters) collectFilterSpecColumns(filters).flatMap((c) =>
|
|
9094
|
-
const obj = parseJson(c);
|
|
9095
|
-
return obj.type === "column" ? [obj.id] : [];
|
|
9096
|
-
}).forEach((c) => hiddenColumns.delete(c));
|
|
11944
|
+
if (filters) collectFilterSpecColumns(filters).flatMap((c) => c.type === "column" ? [c.id] : []).forEach((c) => hiddenColumns.delete(c));
|
|
9097
11945
|
const visibleColumns = columns.filter((c) => !hiddenColumns.has(c.id));
|
|
9098
11946
|
const visibleLabelColumns = getMatchingLabelColumns(visibleColumns.map(getColumnIdAndSpec), allLabelColumns);
|
|
9099
11947
|
if (!allPColumnsReady([...visibleColumns, ...visibleLabelColumns])) return void 0;
|
|
@@ -9101,7 +11949,7 @@ function createPlDataTableV2(ctx, columns, tableState, options) {
|
|
|
9101
11949
|
columns: visibleColumns,
|
|
9102
11950
|
labelColumns: visibleLabelColumns,
|
|
9103
11951
|
coreJoinType,
|
|
9104
|
-
filters,
|
|
11952
|
+
filters: filters ?? null,
|
|
9105
11953
|
sorting,
|
|
9106
11954
|
coreColumnPredicate
|
|
9107
11955
|
});
|
|
@@ -9112,9 +11960,53 @@ function createPlDataTableV2(ctx, columns, tableState, options) {
|
|
|
9112
11960
|
fullTableHandle: fullHandle,
|
|
9113
11961
|
fullPframeHandle: pframeHandle,
|
|
9114
11962
|
visibleTableHandle: visibleHandle,
|
|
9115
|
-
defaultFilters
|
|
11963
|
+
defaultFilters: defaultFilters ?? void 0
|
|
9116
11964
|
};
|
|
9117
11965
|
}
|
|
11966
|
+
/** Rewrite filter column refs through the resolver; throw on any unresolved ref. */
|
|
11967
|
+
function remapFiltersThrowing(filters, resolver, label) {
|
|
11968
|
+
if (isNil$1(filters)) return filters;
|
|
11969
|
+
return traverseFilterSpec(filters, {
|
|
11970
|
+
leaf: (leaf) => {
|
|
11971
|
+
if (leaf.type === void 0) return leaf;
|
|
11972
|
+
const result = { ...leaf };
|
|
11973
|
+
if ("column" in result) {
|
|
11974
|
+
const c = resolver(result.column);
|
|
11975
|
+
if (isNil$1(c)) throw new Error(`Invalid ${label} column ${JSON.stringify(result.column)}: column reference does not match the table columns`);
|
|
11976
|
+
result.column = c;
|
|
11977
|
+
}
|
|
11978
|
+
if ("rhs" in result) {
|
|
11979
|
+
const c = resolver(result.rhs);
|
|
11980
|
+
if (isNil$1(c)) throw new Error(`Invalid ${label} column ${JSON.stringify(result.rhs)}: column reference does not match the table columns`);
|
|
11981
|
+
result.rhs = c;
|
|
11982
|
+
}
|
|
11983
|
+
return result;
|
|
11984
|
+
},
|
|
11985
|
+
and: (results) => ({
|
|
11986
|
+
type: "and",
|
|
11987
|
+
filters: results
|
|
11988
|
+
}),
|
|
11989
|
+
or: (results) => ({
|
|
11990
|
+
type: "or",
|
|
11991
|
+
filters: results
|
|
11992
|
+
}),
|
|
11993
|
+
not: (result) => ({
|
|
11994
|
+
type: "not",
|
|
11995
|
+
filter: result
|
|
11996
|
+
})
|
|
11997
|
+
});
|
|
11998
|
+
}
|
|
11999
|
+
/** Rewrite sorting column refs through the resolver; throw on any unresolved ref. */
|
|
12000
|
+
function remapSortingThrowing(sorting, resolver) {
|
|
12001
|
+
return sorting.map((s) => {
|
|
12002
|
+
const c = resolver(s.column);
|
|
12003
|
+
if (isNil$1(c)) throw new Error(`Invalid sorting column ${JSON.stringify(s.column)}: column reference does not match the table columns`);
|
|
12004
|
+
return {
|
|
12005
|
+
...s,
|
|
12006
|
+
column: c
|
|
12007
|
+
};
|
|
12008
|
+
});
|
|
12009
|
+
}
|
|
9118
12010
|
function getAllLabelColumns(resultPool) {
|
|
9119
12011
|
return new PColumnCollection().addAxisLabelProvider(resultPool).addColumnProvider(resultPool).getColumns({
|
|
9120
12012
|
name: PColumnName.Label,
|