@jbrowse/core 5.0.0-beta.4 → 5.0.0-beta.7
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/README.md +278 -250
- package/esm/PluginManager.js +1 -1
- package/esm/ReExports/publicUi.d.ts +1 -1
- package/esm/ReExports/publicUi.js +1 -1
- package/esm/ReExports/publicUtil.d.ts +1 -1
- package/esm/ReExports/publicUtil.js +1 -1
- package/esm/ReExports/workerNamespaceNames.js +3 -9
- package/esm/assemblyManager/assemblyConfigSchema.d.ts +2 -1
- package/esm/assemblyManager/assemblyConfigSchema.js +2 -1
- package/esm/assemblyManager/expandAssemblyConfigShorthand.d.ts +15 -15
- package/esm/assemblyManager/expandAssemblyConfigShorthand.js +34 -18
- package/esm/configuration/configurationSchema.d.ts +1 -2
- package/esm/configuration/configurationSchema.js +3 -8
- package/esm/configuration/configurationSlot.d.ts +0 -47
- package/esm/configuration/configurationSlot.js +4 -54
- package/esm/configuration/fillLocations.d.ts +14 -0
- package/esm/configuration/fillLocations.js +14 -0
- package/esm/configuration/fullConfSnapshot.d.ts +0 -15
- package/esm/configuration/fullConfSnapshot.js +0 -28
- package/esm/configuration/getConf.d.ts +4 -34
- package/esm/configuration/getConf.js +3 -38
- package/esm/configuration/index.d.ts +3 -4
- package/esm/configuration/index.js +3 -2
- package/esm/configuration/schemaRegistry.d.ts +1 -2
- package/esm/configuration/schemaRegistry.js +1 -2
- package/esm/configuration/slotFacade.d.ts +1 -16
- package/esm/configuration/slotFacade.js +1 -2
- package/esm/configuration/tabixShorthand.js +3 -3
- package/esm/configuration/types.d.ts +4 -16
- package/esm/data_adapters/CytobandAdapter/configSchema.js +3 -4
- package/esm/pluggableElementTypes/DisplayType.d.ts +5 -3
- package/esm/pluggableElementTypes/DisplayType.js +3 -1
- package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +30 -0
- package/esm/pluggableElementTypes/models/BaseTrackModel.js +45 -17
- package/esm/rpc/RpcRegistry.d.ts +7 -1
- package/esm/rpc/coreRpcMethods.d.ts +1 -0
- package/esm/rpc/coreRpcMethods.js +1 -0
- package/esm/rpc/methods/CoreEncodeFeatures.d.ts +15 -0
- package/esm/rpc/methods/CoreEncodeFeatures.js +62 -0
- package/esm/svg/svgId.d.ts +1 -1
- package/esm/svg/svgId.js +1 -1
- package/esm/ui/LegendSwatchGlyph.js +26 -21
- package/esm/ui/MenuTypes.d.ts +5 -52
- package/esm/ui/SizeSliderRow.d.ts +1 -3
- package/esm/ui/SizeSliderRow.js +4 -6
- package/esm/ui/SvgColorLegend.d.ts +9 -3
- package/esm/ui/SvgColorLegend.js +74 -33
- package/esm/ui/colorScale.d.ts +64 -0
- package/esm/ui/colorScale.js +41 -0
- package/esm/ui/colors.d.ts +11 -0
- package/esm/ui/colors.js +7 -0
- package/esm/ui/index.d.ts +5 -7
- package/esm/ui/index.js +3 -13
- package/esm/ui/legendMenuItem.d.ts +5 -16
- package/esm/ui/legendMenuItem.js +3 -14
- package/esm/ui/legendSpec.d.ts +11 -5
- package/esm/ui/legendSpec.js +8 -11
- package/esm/ui/makeSizeMenu.d.ts +0 -6
- package/esm/ui/makeSizeMenu.js +6 -30
- package/esm/ui/measureLegendText.js +1 -1
- package/esm/ui/menuItemAdornment.d.ts +9 -19
- package/esm/ui/menuItemAdornment.js +10 -31
- package/esm/ui/menuItems.d.ts +2 -6
- package/esm/ui/menuItems.js +0 -4
- package/esm/ui/palette.js +2 -1
- package/esm/ui/toggleMenuItems.d.ts +6 -13
- package/esm/ui/toggleMenuItems.js +13 -29
- package/esm/util/colorRamp.d.ts +3 -3
- package/esm/util/colorRamp.js +2 -2
- package/esm/util/featureTransforms.d.ts +15 -0
- package/esm/util/featureTransforms.js +342 -0
- package/esm/util/freezeDeep.d.ts +8 -10
- package/esm/util/freezeDeep.js +8 -10
- package/esm/util/glyphNames.d.ts +8 -0
- package/esm/util/glyphNames.js +12 -0
- package/esm/util/index.d.ts +0 -1
- package/esm/util/index.js +0 -1
- package/esm/util/markEncoding.d.ts +76 -0
- package/esm/util/markEncoding.js +436 -0
- package/esm/util/markEncodingTypes.d.ts +331 -0
- package/esm/util/markEncodingTypes.js +8 -0
- package/esm/util/renderToStaticMarkup.js +1 -1
- package/esm/util/starFusion.d.ts +26 -0
- package/esm/util/starFusion.js +37 -0
- package/esm/util/trackConfigDelta.d.ts +4 -8
- package/esm/util/trackConfigDelta.js +2 -4
- package/esm/util/tracks.d.ts +7 -1
- package/esm/util/tracks.js +72 -7
- package/esm/util/types/index.d.ts +12 -4
- package/esm/util/whenViewSettled.d.ts +9 -0
- package/esm/util/whenViewSettled.js +12 -4
- package/package.json +13 -3
- package/esm/configuration/promotableDefaults.d.ts +0 -234
- package/esm/configuration/promotableDefaults.js +0 -395
- package/esm/configuration/promotablePin.d.ts +0 -65
- package/esm/configuration/promotablePin.js +0 -1
- package/esm/configuration/promotableResolve.d.ts +0 -108
- package/esm/configuration/promotableResolve.js +0 -117
- package/esm/configuration/promotableSlots.d.ts +0 -12
- package/esm/configuration/promotableSlots.js +0 -45
- package/esm/configuration/slotShape.d.ts +0 -12
- package/esm/configuration/slotShape.js +0 -84
- package/esm/ui/PinAdornment.d.ts +0 -5
- package/esm/ui/PinAdornment.js +0 -67
- package/esm/ui/SvgGradientLegend.d.ts +0 -26
- package/esm/ui/SvgGradientLegend.js +0 -26
- package/esm/ui/promotablePinCoverage.d.ts +0 -58
- package/esm/ui/promotablePinCoverage.js +0 -124
- package/esm/util/openDisplays.d.ts +0 -23
- package/esm/util/openDisplays.js +0 -79
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { AnyConfigurationModel, AnyConfigurationSnapshot, ConfigurationSchemaForModel, ConfigurationSlotName, ConfigurationSlotValue, ConfigurationSlotValueResolved } from './types.ts';
|
|
1
|
+
import type { AnyConfigurationModel, AnyConfigurationSnapshot, ConfigurationSchemaForModel, ConfigurationSlotName, ConfigurationSlotValue } from './types.ts';
|
|
3
2
|
/**
|
|
4
3
|
* #api core/configuration
|
|
5
4
|
* Reads a configuration value from a state model that has a `.configuration`
|
|
@@ -12,12 +11,6 @@ import type { AnyConfigurationModel, AnyConfigurationSnapshot, ConfigurationSche
|
|
|
12
11
|
* It does not consult the session and has no per-slot behavior; what you read is
|
|
13
12
|
* what the track stores.
|
|
14
13
|
*
|
|
15
|
-
* A `promotable` slot read this way therefore yields the raw stored value,
|
|
16
|
-
* `undefined` included — that `undefined` is the cascade's inherit sentinel, and
|
|
17
|
-
* `resolveConf` is what turns it into a real value. The read type keeps the
|
|
18
|
-
* `undefined` on purpose, so reaching for the wrong reader is a compile error
|
|
19
|
-
* rather than a silent one.
|
|
20
|
-
*
|
|
21
14
|
* @param model - object containing a 'configuration' member
|
|
22
15
|
* @param slotPaths - array of paths to read
|
|
23
16
|
* @param args - extra arguments e.g. for a feature callback,
|
|
@@ -29,29 +22,6 @@ export declare function getConf(model: {
|
|
|
29
22
|
export declare function getConf<CONFMODEL extends AnyConfigurationModel, SLOT extends ConfigurationSlotName<ConfigurationSchemaForModel<CONFMODEL>> | string[] = ConfigurationSlotName<ConfigurationSchemaForModel<CONFMODEL>>>(model: {
|
|
30
23
|
configuration: CONFMODEL;
|
|
31
24
|
}, slotPath: SLOT, args?: Record<string, unknown>): SLOT extends string ? ConfigurationSlotValue<ConfigurationSchemaForModel<CONFMODEL>, SLOT> : any;
|
|
32
|
-
/**
|
|
33
|
-
* #api core/configuration
|
|
34
|
-
* Reads a `promotable` slot through the display-type-default cascade — the
|
|
35
|
-
* track's own value, else the session-wide promoted default for this display
|
|
36
|
-
* type, else the slot's `promotedBase`. Always yields a real value, never the
|
|
37
|
-
* `undefined` inherit sentinel, so a display's value getter is
|
|
38
|
-
* `get displayMode(): DisplayMode { return resolveConf(self, 'displayMode') }`
|
|
39
|
-
* with no post-guard and no cast.
|
|
40
|
-
*
|
|
41
|
-
* Separate from `getConf` rather than folded into it, deliberately: resolution
|
|
42
|
-
* consults the session, so it is main-thread only and throws on a detached node.
|
|
43
|
-
* Folding it in was built and reverted — ADR-046.
|
|
44
|
-
*
|
|
45
|
-
* Throws if `slot` isn't promotable — the cascade has nothing to say about a
|
|
46
|
-
* plain slot, and `getConf` is what you want there.
|
|
47
|
-
*
|
|
48
|
-
* Takes no jexl `args`, unlike `getConf`: a promotable slot cannot hold a
|
|
49
|
-
* callback (see `SlotResolution`), so there is no per-feature context to supply.
|
|
50
|
-
*
|
|
51
|
-
* @param model - the display state model (needs the session + display type)
|
|
52
|
-
* @param slot - the promotable slot to resolve
|
|
53
|
-
*/
|
|
54
|
-
export declare function resolveConf<CONFMODEL extends AnyConfigurationModel, SLOT extends ConfigurationSlotName<ConfigurationSchemaForModel<CONFMODEL>> = ConfigurationSlotName<ConfigurationSchemaForModel<CONFMODEL>>>(model: ResolvableDisplay<CONFMODEL>, slot: SLOT): ConfigurationSlotValueResolved<ConfigurationSchemaForModel<CONFMODEL>, SLOT>;
|
|
55
25
|
/**
|
|
56
26
|
* #api core/configuration
|
|
57
27
|
* Write counterpart to `getConf`: sets a slot on a state model that has a
|
|
@@ -75,9 +45,9 @@ export declare function resolveConf<CONFMODEL extends AnyConfigurationModel, SLO
|
|
|
75
45
|
* `HostChecksSlotNames` pins each one.
|
|
76
46
|
*
|
|
77
47
|
* A wrong *value* type still throws at runtime (MST type-checks the assignment)
|
|
78
|
-
* rather than at compile time. `value` is deliberately `unknown` because
|
|
79
|
-
*
|
|
80
|
-
*
|
|
48
|
+
* rather than at compile time. `value` is deliberately `unknown` because
|
|
49
|
+
* `undefined` is a legitimate write — it resets a slot to its schema default —
|
|
50
|
+
* and the declared slot value type doesn't include it.
|
|
81
51
|
*
|
|
82
52
|
* @param model - object containing a 'configuration' member
|
|
83
53
|
* @param slotName - the slot to write
|
|
@@ -1,42 +1,7 @@
|
|
|
1
|
-
import { resolveSlot } from './promotableResolve.js';
|
|
2
1
|
import { readConfObject } from './readConfObject.js';
|
|
3
2
|
export function getConf(model, slotPath, args = {}) {
|
|
4
3
|
return readConfObject(model.configuration, slotPath, args);
|
|
5
4
|
}
|
|
6
|
-
/**
|
|
7
|
-
* #api core/configuration
|
|
8
|
-
* Reads a `promotable` slot through the display-type-default cascade — the
|
|
9
|
-
* track's own value, else the session-wide promoted default for this display
|
|
10
|
-
* type, else the slot's `promotedBase`. Always yields a real value, never the
|
|
11
|
-
* `undefined` inherit sentinel, so a display's value getter is
|
|
12
|
-
* `get displayMode(): DisplayMode { return resolveConf(self, 'displayMode') }`
|
|
13
|
-
* with no post-guard and no cast.
|
|
14
|
-
*
|
|
15
|
-
* Separate from `getConf` rather than folded into it, deliberately: resolution
|
|
16
|
-
* consults the session, so it is main-thread only and throws on a detached node.
|
|
17
|
-
* Folding it in was built and reverted — ADR-046.
|
|
18
|
-
*
|
|
19
|
-
* Throws if `slot` isn't promotable — the cascade has nothing to say about a
|
|
20
|
-
* plain slot, and `getConf` is what you want there.
|
|
21
|
-
*
|
|
22
|
-
* Takes no jexl `args`, unlike `getConf`: a promotable slot cannot hold a
|
|
23
|
-
* callback (see `SlotResolution`), so there is no per-feature context to supply.
|
|
24
|
-
*
|
|
25
|
-
* @param model - the display state model (needs the session + display type)
|
|
26
|
-
* @param slot - the promotable slot to resolve
|
|
27
|
-
*/
|
|
28
|
-
export function resolveConf(
|
|
29
|
-
// the display state node itself, not just its `.configuration`: the cascade
|
|
30
|
-
// keys the session-wide tier on `type` and reaches the session through the
|
|
31
|
-
// node. Asking for that shape is what keeps this cast-free — hand it a bare
|
|
32
|
-
// config holder and tsc names the missing members instead of failing at the
|
|
33
|
-
// first read. `ResolvableDisplay<CONFMODEL>`, never
|
|
34
|
-
// `ResolvableDisplay & { configuration: CONFMODEL }`: the intersection
|
|
35
|
-
// re-widens the slot names to `string` (see `ResolvableDisplay`)
|
|
36
|
-
model, slot) {
|
|
37
|
-
// the resolution is `unknown`, which the declared return type can't infer
|
|
38
|
-
return resolveSlot(model, slot).value;
|
|
39
|
-
}
|
|
40
5
|
/**
|
|
41
6
|
* #api core/configuration
|
|
42
7
|
* Write counterpart to `getConf`: sets a slot on a state model that has a
|
|
@@ -60,9 +25,9 @@ model, slot) {
|
|
|
60
25
|
* `HostChecksSlotNames` pins each one.
|
|
61
26
|
*
|
|
62
27
|
* A wrong *value* type still throws at runtime (MST type-checks the assignment)
|
|
63
|
-
* rather than at compile time. `value` is deliberately `unknown` because
|
|
64
|
-
*
|
|
65
|
-
*
|
|
28
|
+
* rather than at compile time. `value` is deliberately `unknown` because
|
|
29
|
+
* `undefined` is a legitimate write — it resets a slot to its schema default —
|
|
30
|
+
* and the declared slot value type doesn't include it.
|
|
66
31
|
*
|
|
67
32
|
* @param model - object containing a 'configuration' member
|
|
68
33
|
* @param slotName - the slot to write
|
|
@@ -7,13 +7,12 @@ export { FormatAboutConfigSchemaFactory } from './formatAboutConfigSchema.ts';
|
|
|
7
7
|
export { DEFAULT_FORMAT_DETAILS_DEPTH, FormatDetailsConfigSchemaFactory, } from './formatDetailsConfigSchema.ts';
|
|
8
8
|
export { mergeFormatCallbacks } from './mergeFormatCallbacks.ts';
|
|
9
9
|
export { readConfObject, readConfSlot, readConfigValue, } from './readConfObject.ts';
|
|
10
|
-
export { getConf,
|
|
10
|
+
export { getConf, setConf } from './getConf.ts';
|
|
11
|
+
export { fillLocations } from './fillLocations.ts';
|
|
11
12
|
export { expandTabixShorthand, tabixIndexSnapshot } from './tabixShorthand.ts';
|
|
12
13
|
export { tabixIndexFields } from './tabixIndexFields.ts';
|
|
13
14
|
export { evaluateJexl, isCallbackValue } from './slotValueUtils.ts';
|
|
14
15
|
export { toCallbackValue, toFixedValue } from './configurationSlot.ts';
|
|
15
16
|
export { getSlotDefinition, isConfigurationSlot, makeSlotFacade, preProcessSlotValues, slotChoices, } from './slotFacade.ts';
|
|
16
17
|
export type { SlotFacade } from './slotFacade.ts';
|
|
17
|
-
export
|
|
18
|
-
export { clearPromotedDefaults, getDisplayTypeDefaultChanges, isSlotCustomized, makePin, makeTogglePin, getConfigSnapshotWithPromotables, getTrackConfigWithPromotables, } from './promotableDefaults.ts';
|
|
19
|
-
export type { Pin, ResolvedConfigSnapshot, TogglePin, TrackConfigWithPromotables, ValuePin, } from './promotableDefaults.ts';
|
|
18
|
+
export { fullConfSnapshot } from './fullConfSnapshot.ts';
|
|
@@ -10,10 +10,11 @@ export { FormatAboutConfigSchemaFactory } from './formatAboutConfigSchema.js';
|
|
|
10
10
|
export { DEFAULT_FORMAT_DETAILS_DEPTH, FormatDetailsConfigSchemaFactory, } from './formatDetailsConfigSchema.js';
|
|
11
11
|
export { mergeFormatCallbacks } from './mergeFormatCallbacks.js';
|
|
12
12
|
export { readConfObject, readConfSlot, readConfigValue, } from './readConfObject.js';
|
|
13
|
-
export { getConf,
|
|
13
|
+
export { getConf, setConf } from './getConf.js';
|
|
14
|
+
export { fillLocations } from './fillLocations.js';
|
|
14
15
|
export { expandTabixShorthand, tabixIndexSnapshot } from './tabixShorthand.js';
|
|
15
16
|
export { tabixIndexFields } from './tabixIndexFields.js';
|
|
16
17
|
export { evaluateJexl, isCallbackValue } from './slotValueUtils.js';
|
|
17
18
|
export { toCallbackValue, toFixedValue } from './configurationSlot.js';
|
|
18
19
|
export { getSlotDefinition, isConfigurationSlot, makeSlotFacade, preProcessSlotValues, slotChoices, } from './slotFacade.js';
|
|
19
|
-
export {
|
|
20
|
+
export { fullConfSnapshot } from './fullConfSnapshot.js';
|
|
@@ -17,8 +17,7 @@ export declare function isRegisteredConfigurationSchema(type: IAnyType): boolean
|
|
|
17
17
|
* The slot/sub-schema/constant table for a config (includes slots merged in from
|
|
18
18
|
* `baseConfiguration` at schema construction). Undefined when the argument isn't
|
|
19
19
|
* a registered configuration schema. The single accessor for "what are this
|
|
20
|
-
* config's slots?" — shared by the slot facade
|
|
21
|
-
* `fullConfSnapshot`.
|
|
20
|
+
* config's slots?" — shared by the slot facade and `fullConfSnapshot`.
|
|
22
21
|
*
|
|
23
22
|
* Takes a live node *or* the schema type itself. Every in-tree reader holds a
|
|
24
23
|
* node, which is why the `getType` hop is here; a caller enumerating registered
|
|
@@ -28,8 +28,7 @@ export function isRegisteredConfigurationSchema(type) {
|
|
|
28
28
|
* The slot/sub-schema/constant table for a config (includes slots merged in from
|
|
29
29
|
* `baseConfiguration` at schema construction). Undefined when the argument isn't
|
|
30
30
|
* a registered configuration schema. The single accessor for "what are this
|
|
31
|
-
* config's slots?" — shared by the slot facade
|
|
32
|
-
* `fullConfSnapshot`.
|
|
31
|
+
* config's slots?" — shared by the slot facade and `fullConfSnapshot`.
|
|
33
32
|
*
|
|
34
33
|
* Takes a live node *or* the schema type itself. Every in-tree reader holds a
|
|
35
34
|
* node, which is why the `getType` hop is here; a caller enumerating registered
|
|
@@ -32,20 +32,6 @@ export interface SlotFacade {
|
|
|
32
32
|
type: ConfigSlotType;
|
|
33
33
|
contextVariable: string[];
|
|
34
34
|
defaultValue: unknown;
|
|
35
|
-
/**
|
|
36
|
-
* For a `promotable` slot, the value its unset state resolves to when nothing
|
|
37
|
-
* is promoted (see `promotableResolve.ts`). Undefined on a plain slot, whose
|
|
38
|
-
* `defaultValue` is already the concrete value.
|
|
39
|
-
*
|
|
40
|
-
* Here because a promotable slot's `defaultValue` is always the `undefined`
|
|
41
|
-
* inherit sentinel, so an editor rendering `defaultValue` for an unset slot
|
|
42
|
-
* shows nothing at all — for a `maybeBoolean` that reads as a concrete
|
|
43
|
-
* `false`, which is wrong for every slot whose base is `true`. The editor
|
|
44
|
-
* still cannot see the *session* tier of the cascade (its target is often a
|
|
45
|
-
* detached config node), so this is the honest answer it can give: what unset
|
|
46
|
-
* means with nothing promoted.
|
|
47
|
-
*/
|
|
48
|
-
promotedBase?: unknown;
|
|
49
35
|
/** enum choices, present only for `stringEnum`/`maybeStringEnum` slots */
|
|
50
36
|
choices?: string[];
|
|
51
37
|
pluginManager: PluginManager;
|
|
@@ -54,8 +40,7 @@ export interface SlotFacade {
|
|
|
54
40
|
* Whether the slot holds a non-default value. Each slot is `stripDefault`-
|
|
55
41
|
* wrapped, so an at-default slot is omitted from the config snapshot — the
|
|
56
42
|
* same signal the persistence/delta layer uses (robust for map/array slots
|
|
57
|
-
* where a live-value `deepEqual` against the plain default would misfire).
|
|
58
|
-
* a promotable slot, "non-default" means customized rather than inheriting.
|
|
43
|
+
* where a live-value `deepEqual` against the plain default would misfire).
|
|
59
44
|
*/
|
|
60
45
|
readonly modified: boolean;
|
|
61
46
|
set: (val: unknown) => void;
|
|
@@ -66,14 +66,13 @@ export function getSlotDefinition(node, slotName) {
|
|
|
66
66
|
}
|
|
67
67
|
export function makeSlotFacade(node, slotName) {
|
|
68
68
|
const definition = getSlotDefinition(node, slotName);
|
|
69
|
-
const { type, description = '', defaultValue,
|
|
69
|
+
const { type, description = '', defaultValue, contextVariable = [], } = definition;
|
|
70
70
|
return {
|
|
71
71
|
name: slotName,
|
|
72
72
|
description,
|
|
73
73
|
type,
|
|
74
74
|
contextVariable,
|
|
75
75
|
defaultValue,
|
|
76
|
-
promotedBase,
|
|
77
76
|
choices: slotChoices(definition),
|
|
78
77
|
pluginManager: getEnv(node).pluginManager,
|
|
79
78
|
get value() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { fillLocations } from './fillLocations.js';
|
|
1
2
|
/**
|
|
2
3
|
* The `index` half of a tabix-indexed adapter's shorthand snapshot: given
|
|
3
4
|
* `{ uri, baseUri?, csi? }`, where the index file sits and what kind it is.
|
|
@@ -36,10 +37,9 @@ export function tabixIndexSnapshot(snap) {
|
|
|
36
37
|
*/
|
|
37
38
|
export function expandTabixShorthand(snap, locationKey) {
|
|
38
39
|
return snap.uri
|
|
39
|
-
? {
|
|
40
|
-
...snap,
|
|
40
|
+
? fillLocations(snap, {
|
|
41
41
|
[locationKey]: { uri: snap.uri, baseUri: snap.baseUri },
|
|
42
42
|
index: tabixIndexSnapshot(snap),
|
|
43
|
-
}
|
|
43
|
+
})
|
|
44
44
|
: snap;
|
|
45
45
|
}
|
|
@@ -23,7 +23,7 @@ export type ConfigurationSlotName<SCHEMA> = SCHEMA extends undefined ? never : S
|
|
|
23
23
|
* every value left `unknown`.
|
|
24
24
|
*
|
|
25
25
|
* Names are the whole point of it. A slot value can be its own type, a `jexl:`
|
|
26
|
-
* callback string, or (for a
|
|
26
|
+
* callback string, or (for a `maybe*` slot) absent, and nothing here tries to
|
|
27
27
|
* check that; a *name* the schema does not declare is dropped on the way in
|
|
28
28
|
* without a word, so `preferance` is a setting that reads as applied and never
|
|
29
29
|
* applies. Against an object literal — which is how an embedder writes one —
|
|
@@ -34,11 +34,6 @@ export type ConfigurationSnapshot<SCHEMA> = SCHEMA extends undefined ? never : S
|
|
|
34
34
|
} & {
|
|
35
35
|
[K in GetExplicitIdentifier<SCHEMA>]?: string;
|
|
36
36
|
} & (GetBase<SCHEMA> extends ConfigurationSchemaType<any, any> ? ConfigurationSnapshot<GetBase<SCHEMA>> : unknown) : unknown;
|
|
37
|
-
type SlotValueResolvedFromDef<DEF> = DEF extends {
|
|
38
|
-
promotedBase: undefined;
|
|
39
|
-
} ? SlotValueRawFromDef<DEF> : DEF extends {
|
|
40
|
-
promotedBase: unknown;
|
|
41
|
-
} ? Exclude<SlotValueRawFromDef<DEF>, undefined> : SlotValueRawFromDef<DEF>;
|
|
42
37
|
/**
|
|
43
38
|
* The value each builtin slot `type` reads as — the type-level twin of
|
|
44
39
|
* `slotTypes` in `configurationSlot.ts`, which is the same list as MST models.
|
|
@@ -66,9 +61,8 @@ interface SlotValueByType {
|
|
|
66
61
|
* only add cast ceremony on values that are legitimately dynamic.
|
|
67
62
|
*
|
|
68
63
|
* Stated here rather than left to the `defaultValue` fallback, which reaches
|
|
69
|
-
* `any` for these only by accident:
|
|
70
|
-
*
|
|
71
|
-
* always the `undefined` sentinel.
|
|
64
|
+
* `any` for these only by accident: no `frozen` slot in the repo happens to
|
|
65
|
+
* default to a scalar.
|
|
72
66
|
*/
|
|
73
67
|
frozen: any;
|
|
74
68
|
maybeFrozen: any;
|
|
@@ -106,11 +100,6 @@ type SlotValueRawFromDef<DEF> = DEF extends AnyConfigurationSchemaType ? AnyConf
|
|
|
106
100
|
} ? [V] extends [boolean] ? boolean : [V] extends [string] ? string : [V] extends [number] ? number : any : any;
|
|
107
101
|
/** what a raw read (`getConf` / `readConfObject`) of this slot yields */
|
|
108
102
|
export type ConfigurationSlotValue<SCHEMA, K extends string> = SCHEMA extends ConfigurationSchemaType<infer D, any> ? K extends keyof D ? SlotValueRawFromDef<D[K]> : GetBase<SCHEMA> extends ConfigurationSchemaType<any, any> ? ConfigurationSlotValue<GetBase<SCHEMA>, K> : any : any;
|
|
109
|
-
/**
|
|
110
|
-
* what `resolveConf` yields: the same, minus the inherit sentinel on a
|
|
111
|
-
* promotable slot — the cascade always produces a real value.
|
|
112
|
-
*/
|
|
113
|
-
export type ConfigurationSlotValueResolved<SCHEMA, K extends string> = SCHEMA extends ConfigurationSchemaType<infer D, any> ? K extends keyof D ? SlotValueResolvedFromDef<D[K]> : GetBase<SCHEMA> extends ConfigurationSchemaType<any, any> ? ConfigurationSlotValueResolved<GetBase<SCHEMA>, K> : any : any;
|
|
114
103
|
/**
|
|
115
104
|
* Naming convention for config types, paired per schema:
|
|
116
105
|
* - `XConfigSchema` is the MST IType (the schema itself). Use it for
|
|
@@ -154,8 +143,7 @@ export type ConfigModelForFields<FIELDS extends ConfigurationSchemaDefinition, B
|
|
|
154
143
|
* ```
|
|
155
144
|
*
|
|
156
145
|
* Worth a named type because the widened form has **no symptom** — a mixin host
|
|
157
|
-
* cast to `AnyConfigurationModel
|
|
158
|
-
* intersection that re-widens, compiles and runs and checks nothing. Every
|
|
146
|
+
* cast to `AnyConfigurationModel` compiles and runs and checks nothing. Every
|
|
159
147
|
* misspelled slot name below it typechecks, and a misspelled *read* returns
|
|
160
148
|
* `undefined` with no diagnostic at any layer, so only a sabotage or this
|
|
161
149
|
* assertion tells the two apart.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConfigurationSchema } from '../../configuration/index.js';
|
|
1
|
+
import { ConfigurationSchema, fillLocations, } from '../../configuration/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* #config CytobandAdapter
|
|
4
4
|
*
|
|
@@ -55,13 +55,12 @@ const configSchema = ConfigurationSchema('CytobandAdapter', {
|
|
|
55
55
|
preProcessSnapshot: snap => {
|
|
56
56
|
// populate from just snap.uri
|
|
57
57
|
return snap.uri
|
|
58
|
-
? {
|
|
59
|
-
...snap,
|
|
58
|
+
? fillLocations(snap, {
|
|
60
59
|
cytobandLocation: {
|
|
61
60
|
uri: snap.uri,
|
|
62
61
|
baseUri: snap.baseUri,
|
|
63
62
|
},
|
|
64
|
-
}
|
|
63
|
+
})
|
|
65
64
|
: snap;
|
|
66
65
|
},
|
|
67
66
|
});
|
|
@@ -7,9 +7,11 @@ export default class DisplayType extends LazyStateModelElement {
|
|
|
7
7
|
configSchema: AnyConfigurationSchemaType;
|
|
8
8
|
ReactComponent: AnyReactComponentType;
|
|
9
9
|
/**
|
|
10
|
-
* The track type the display
|
|
10
|
+
* The track type the display attaches to, or several: a display that reads
|
|
11
|
+
* a field any feature adapter serves (the Manhattan plot's `score`) belongs
|
|
12
|
+
* to every track type whose adapters serve it.
|
|
11
13
|
*/
|
|
12
|
-
trackType: string;
|
|
14
|
+
trackType: string | string[];
|
|
13
15
|
/**
|
|
14
16
|
* The view type the display is associated with
|
|
15
17
|
*/
|
|
@@ -21,7 +23,7 @@ export default class DisplayType extends LazyStateModelElement {
|
|
|
21
23
|
constructor(stuff: {
|
|
22
24
|
name: string;
|
|
23
25
|
stateModel: IAnyModelType | (() => Promise<IAnyModelType>);
|
|
24
|
-
trackType: string;
|
|
26
|
+
trackType: string | string[];
|
|
25
27
|
viewType: string;
|
|
26
28
|
displayName?: string;
|
|
27
29
|
configSchema: AnyConfigurationSchemaType;
|
|
@@ -4,7 +4,9 @@ export default class DisplayType extends LazyStateModelElement {
|
|
|
4
4
|
configSchema;
|
|
5
5
|
ReactComponent;
|
|
6
6
|
/**
|
|
7
|
-
* The track type the display
|
|
7
|
+
* The track type the display attaches to, or several: a display that reads
|
|
8
|
+
* a field any feature adapter serves (the Manhattan plot's `score`) belongs
|
|
9
|
+
* to every track type whose adapters serve it.
|
|
8
10
|
*/
|
|
9
11
|
trackType;
|
|
10
12
|
/**
|
|
@@ -95,6 +95,22 @@ export declare function createBaseTrackModel(pm: PluginManager, trackType: strin
|
|
|
95
95
|
* a shown track always has at least one display
|
|
96
96
|
*/
|
|
97
97
|
readonly activeDisplay: DisplayModel & import("@jbrowse/mobx-state-tree").IStateTreeNode<IType<unknown, unknown, DisplayModel>>;
|
|
98
|
+
/**
|
|
99
|
+
* #getter
|
|
100
|
+
* the configured displays the CONTAINING VIEW can draw, which is the set
|
|
101
|
+
* `replaceDisplay` will accept
|
|
102
|
+
*
|
|
103
|
+
* `configuration.displays` is not that set: baseTrackConfig injects one
|
|
104
|
+
* entry per display type registered for the track TYPE, across every
|
|
105
|
+
* view type, so a VariantTrack carries a ChordVariantDisplay a linear
|
|
106
|
+
* view cannot draw. The track menu's own "Display types" submenu has
|
|
107
|
+
* always filtered them; this exposes the same list to code, because the
|
|
108
|
+
* alternative is every caller re-deriving it from the plugin manager.
|
|
109
|
+
*/
|
|
110
|
+
readonly compatibleDisplays: (import("@jbrowse/mobx-state-tree").ModelInstanceTypeProps<Record<string, any>> & {
|
|
111
|
+
setSubschema(slotName: string, data: Record<string, unknown>): any;
|
|
112
|
+
setSlot(slotName: string, value: unknown): void;
|
|
113
|
+
} & import("@jbrowse/mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>)[];
|
|
98
114
|
/**
|
|
99
115
|
* #getter
|
|
100
116
|
*/
|
|
@@ -195,6 +211,20 @@ export declare function createBaseTrackModel(pm: PluginManager, trackType: strin
|
|
|
195
211
|
* stops changing.
|
|
196
212
|
*/
|
|
197
213
|
afterAttach(): void;
|
|
214
|
+
} & {
|
|
215
|
+
/**
|
|
216
|
+
* #action
|
|
217
|
+
* The awaitable sibling of `replaceDisplay`: loads the target display's
|
|
218
|
+
* state model, then swaps to it carrying whatever settings the outgoing
|
|
219
|
+
* display can hand over.
|
|
220
|
+
*
|
|
221
|
+
* `replaceDisplay` stays a plain sync action and ASSERTS the model is
|
|
222
|
+
* loaded, and every display state model in this tree is a dynamic import
|
|
223
|
+
* until something shows one — so a caller that has not already shown the
|
|
224
|
+
* target needs this. Named like `launchTrack`, which is the same problem
|
|
225
|
+
* one level up.
|
|
226
|
+
*/
|
|
227
|
+
launchDisplay(displayId: string): Promise<void>;
|
|
198
228
|
} & {
|
|
199
229
|
/**
|
|
200
230
|
* #getter
|
|
@@ -156,6 +156,21 @@ export function createBaseTrackModel(pm, trackType, baseTrackConfig) {
|
|
|
156
156
|
get activeDisplay() {
|
|
157
157
|
return self.displays[0];
|
|
158
158
|
},
|
|
159
|
+
/**
|
|
160
|
+
* #getter
|
|
161
|
+
* the configured displays the CONTAINING VIEW can draw, which is the set
|
|
162
|
+
* `replaceDisplay` will accept
|
|
163
|
+
*
|
|
164
|
+
* `configuration.displays` is not that set: baseTrackConfig injects one
|
|
165
|
+
* entry per display type registered for the track TYPE, across every
|
|
166
|
+
* view type, so a VariantTrack carries a ChordVariantDisplay a linear
|
|
167
|
+
* view cannot draw. The track menu's own "Display types" submenu has
|
|
168
|
+
* always filtered them; this exposes the same list to code, because the
|
|
169
|
+
* alternative is every caller re-deriving it from the plugin manager.
|
|
170
|
+
*/
|
|
171
|
+
get compatibleDisplays() {
|
|
172
|
+
return getCompatibleDisplays(self);
|
|
173
|
+
},
|
|
159
174
|
/**
|
|
160
175
|
* #getter
|
|
161
176
|
*/
|
|
@@ -350,6 +365,28 @@ export function createBaseTrackModel(pm, trackType, baseTrackConfig) {
|
|
|
350
365
|
void releaseAdapterSession(rpcManager, retained);
|
|
351
366
|
});
|
|
352
367
|
},
|
|
368
|
+
}))
|
|
369
|
+
.actions(self => ({
|
|
370
|
+
/**
|
|
371
|
+
* #action
|
|
372
|
+
* The awaitable sibling of `replaceDisplay`: loads the target display's
|
|
373
|
+
* state model, then swaps to it carrying whatever settings the outgoing
|
|
374
|
+
* display can hand over.
|
|
375
|
+
*
|
|
376
|
+
* `replaceDisplay` stays a plain sync action and ASSERTS the model is
|
|
377
|
+
* loaded, and every display state model in this tree is a dynamic import
|
|
378
|
+
* until something shows one — so a caller that has not already shown the
|
|
379
|
+
* target needs this. Named like `launchTrack`, which is the same problem
|
|
380
|
+
* one level up.
|
|
381
|
+
*/
|
|
382
|
+
async launchDisplay(displayId) {
|
|
383
|
+
const displays = self.configuration.displays;
|
|
384
|
+
const { type } = getDisplayConf(displays, displayId);
|
|
385
|
+
await pm.resolveDisplayTypeRecord(type)?.loadStateModel();
|
|
386
|
+
if (isAlive(self)) {
|
|
387
|
+
self.replaceDisplay(self.activeDisplay.configuration.displayId, displayId, self.activeDisplay.getPortableSettings?.(displayId) ?? {});
|
|
388
|
+
}
|
|
389
|
+
},
|
|
353
390
|
}))
|
|
354
391
|
.views(self => ({
|
|
355
392
|
/**
|
|
@@ -430,7 +467,7 @@ export function createBaseTrackModel(pm, trackType, baseTrackConfig) {
|
|
|
430
467
|
trackMenuItems() {
|
|
431
468
|
const menuItems = self.displays.flatMap(d => d.trackMenuItems());
|
|
432
469
|
const shownId = self.activeDisplay.configuration.displayId;
|
|
433
|
-
const compatDisp =
|
|
470
|
+
const compatDisp = self.compatibleDisplays;
|
|
434
471
|
return [
|
|
435
472
|
...menuItems,
|
|
436
473
|
...(compatDisp.length > 1 && shownId
|
|
@@ -451,24 +488,15 @@ export function createBaseTrackModel(pm, trackType, baseTrackConfig) {
|
|
|
451
488
|
// being replaced, so leaving the menu up would keep a
|
|
452
489
|
// list of items built against a destroyed MST node
|
|
453
490
|
keepMenuOpen: false,
|
|
454
|
-
// the chosen display's state
|
|
455
|
-
//
|
|
456
|
-
// itself stays a plain sync action
|
|
491
|
+
// launchDisplay, because the chosen display's state
|
|
492
|
+
// model may still be a dynamic import away
|
|
457
493
|
onClick: () => {
|
|
458
494
|
if (d.displayId !== shownId) {
|
|
459
|
-
void
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
if (isAlive(self)) {
|
|
465
|
-
self.replaceDisplay(shownId, d.displayId, self.activeDisplay.getPortableSettings?.(d.displayId) ?? {});
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
catch (e) {
|
|
469
|
-
getSession(self).notifyError(`${e}`, e);
|
|
470
|
-
}
|
|
471
|
-
})();
|
|
495
|
+
void self
|
|
496
|
+
.launchDisplay(d.displayId)
|
|
497
|
+
.catch((e) => {
|
|
498
|
+
getSession(self).notifyError(`${e}`, e);
|
|
499
|
+
});
|
|
472
500
|
}
|
|
473
501
|
},
|
|
474
502
|
};
|
package/esm/rpc/RpcRegistry.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { FeatureDensity } from '../data_adapters/BaseAdapter/featureDensity.ts';
|
|
2
|
+
import type { CoreEncodeFeaturesArgs, EncodedFeaturesResult } from '../util/markEncodingTypes.ts';
|
|
2
3
|
import type { StatusCallback } from '../util/progress.ts';
|
|
3
4
|
import type { UnwrapRpcResult } from '../util/rpc.ts';
|
|
4
5
|
import type { Feature, SimpleFeatureSerialized } from '../util/simpleFeature.ts';
|
|
5
6
|
import type { StopToken } from '../util/stopToken.ts';
|
|
6
7
|
import type { NoAssemblyRegion } from '../util/types/data.ts';
|
|
7
8
|
import type { RpcResult } from './RpcServer.ts';
|
|
8
|
-
import type { ByteEstimateScope } from './byteBudget.ts';
|
|
9
|
+
import type { ByteEstimateScope, RegionTooLargeResult } from './byteBudget.ts';
|
|
9
10
|
export interface RegionLike {
|
|
10
11
|
refName: string;
|
|
11
12
|
start: number;
|
|
@@ -44,6 +45,11 @@ export interface RpcRegistry {
|
|
|
44
45
|
return: Feature[];
|
|
45
46
|
wire: SimpleFeatureSerialized[];
|
|
46
47
|
};
|
|
48
|
+
CoreEncodeFeatures: {
|
|
49
|
+
args: CoreEncodeFeaturesArgs;
|
|
50
|
+
return: EncodedFeaturesResult | RegionTooLargeResult;
|
|
51
|
+
transferables: EncodedFeaturesResult;
|
|
52
|
+
};
|
|
47
53
|
CoreGetRegionByteEstimate: {
|
|
48
54
|
args: {
|
|
49
55
|
adapterConfig: Record<string, unknown>;
|
|
@@ -2,6 +2,7 @@ export { default as CoreGetRefNames } from './methods/CoreGetRefNames.ts';
|
|
|
2
2
|
export { default as CoreGetMetadata } from './methods/CoreGetMetadata.ts';
|
|
3
3
|
export { default as CoreGetInfo } from './methods/CoreGetInfo.ts';
|
|
4
4
|
export { default as CoreGetFeatures } from './methods/CoreGetFeatures.ts';
|
|
5
|
+
export { default as CoreEncodeFeatures } from './methods/CoreEncodeFeatures.ts';
|
|
5
6
|
export { default as CoreGetSequence } from './methods/CoreGetSequence.ts';
|
|
6
7
|
export { default as CoreFreeResources } from './methods/CoreFreeResources.ts';
|
|
7
8
|
export { default as CoreGetRegionByteEstimate } from './methods/CoreGetRegionByteEstimate.ts';
|
|
@@ -2,6 +2,7 @@ export { default as CoreGetRefNames } from './methods/CoreGetRefNames.js';
|
|
|
2
2
|
export { default as CoreGetMetadata } from './methods/CoreGetMetadata.js';
|
|
3
3
|
export { default as CoreGetInfo } from './methods/CoreGetInfo.js';
|
|
4
4
|
export { default as CoreGetFeatures } from './methods/CoreGetFeatures.js';
|
|
5
|
+
export { default as CoreEncodeFeatures } from './methods/CoreEncodeFeatures.js';
|
|
5
6
|
export { default as CoreGetSequence } from './methods/CoreGetSequence.js';
|
|
6
7
|
export { default as CoreFreeResources } from './methods/CoreFreeResources.js';
|
|
7
8
|
export { default as CoreGetRegionByteEstimate } from './methods/CoreGetRegionByteEstimate.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import RpcMethodTypeWithRenameRegion from '../../pluggableElementTypes/RpcMethodTypeWithRenameRegion.ts';
|
|
2
|
+
import type { EncodedFeaturesResult } from '../../util/markEncoding.ts';
|
|
3
|
+
import type { RpcExecuteArgs } from '../RpcRegistry.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Fetch a region's features once, run the shared transform steps over them,
|
|
6
|
+
* then each layer's own, and evaluate the layer's encoding over what is left
|
|
7
|
+
* in the worker, where the `Feature` objects are, filling the lanes its shape
|
|
8
|
+
* reads. The colours come back packed, the scale tables resolved, and the
|
|
9
|
+
* main thread reads the same table for its legend that the colours were
|
|
10
|
+
* drawn from.
|
|
11
|
+
*/
|
|
12
|
+
export default class CoreEncodeFeatures extends RpcMethodTypeWithRenameRegion<'CoreEncodeFeatures'> {
|
|
13
|
+
name: 'CoreEncodeFeatures';
|
|
14
|
+
execute(args: RpcExecuteArgs<'CoreEncodeFeatures'>): Promise<import("../byteBudget.ts").RegionTooLargeResult | import("../RpcServer.ts").RpcResult<EncodedFeaturesResult>>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { getFeatureAdapterOrThrow } from '../../data_adapters/getFeatureAdapter.js';
|
|
2
|
+
import RpcMethodTypeWithRenameRegion from '../../pluggableElementTypes/RpcMethodTypeWithRenameRegion.js';
|
|
3
|
+
import { runTransforms } from '../../util/featureTransforms.js';
|
|
4
|
+
import { rpcResult } from '../../util/librpc.js';
|
|
5
|
+
import { encodeFeatures, encodedChannelTransferables, } from '../../util/markEncoding.js';
|
|
6
|
+
import { createProgressReporter, updateStatus } from '../../util/progress.js';
|
|
7
|
+
import { checkStopTokenThrottled, createStopTokenChecker, } from '../../util/stopToken.js';
|
|
8
|
+
import { measureRegionBytes } from '../byteBudget.js';
|
|
9
|
+
/**
|
|
10
|
+
* Fetch a region's features once, run the shared transform steps over them,
|
|
11
|
+
* then each layer's own, and evaluate the layer's encoding over what is left
|
|
12
|
+
* in the worker, where the `Feature` objects are, filling the lanes its shape
|
|
13
|
+
* reads. The colours come back packed, the scale tables resolved, and the
|
|
14
|
+
* main thread reads the same table for its legend that the colours were
|
|
15
|
+
* drawn from.
|
|
16
|
+
*/
|
|
17
|
+
export default class CoreEncodeFeatures extends RpcMethodTypeWithRenameRegion {
|
|
18
|
+
name = 'CoreEncodeFeatures';
|
|
19
|
+
async execute(args) {
|
|
20
|
+
const { sessionId, adapterConfig, sequenceAdapter, region, layers: requested, transform = [], filters = [], byteLimit, stopToken, statusCallback, } = args;
|
|
21
|
+
const { pluginManager } = this;
|
|
22
|
+
const stopTokenCheck = createStopTokenChecker(stopToken);
|
|
23
|
+
const dataAdapter = await getFeatureAdapterOrThrow({
|
|
24
|
+
pluginManager,
|
|
25
|
+
sessionId,
|
|
26
|
+
adapterConfig,
|
|
27
|
+
sequenceAdapter,
|
|
28
|
+
});
|
|
29
|
+
const { bytes, tooLarge } = await measureRegionBytes({
|
|
30
|
+
dataAdapter,
|
|
31
|
+
regions: [region],
|
|
32
|
+
byteLimit,
|
|
33
|
+
stopToken,
|
|
34
|
+
statusCallback,
|
|
35
|
+
stopTokenCheck,
|
|
36
|
+
});
|
|
37
|
+
if (tooLarge) {
|
|
38
|
+
return tooLarge;
|
|
39
|
+
}
|
|
40
|
+
const fetched = await updateStatus('Downloading features', statusCallback, () => dataAdapter.getFeaturesArray(region, { statusCallback, stopToken }));
|
|
41
|
+
checkStopTokenThrottled(stopTokenCheck);
|
|
42
|
+
const { jexl } = pluginManager;
|
|
43
|
+
const shared = runTransforms(fetched, [
|
|
44
|
+
...filters.map(expr => ({ type: 'filter', expr })),
|
|
45
|
+
...transform,
|
|
46
|
+
], jexl);
|
|
47
|
+
const layers = requested.map(({ encoding, lanes, transform: own }) => {
|
|
48
|
+
const features = own ? runTransforms(shared, own, jexl) : shared;
|
|
49
|
+
return encodeFeatures(features, encoding, lanes, {
|
|
50
|
+
jexl,
|
|
51
|
+
report: createProgressReporter({
|
|
52
|
+
label: 'Encoding features',
|
|
53
|
+
total: features.length,
|
|
54
|
+
statusCallback,
|
|
55
|
+
stopTokenCheck,
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
const result = { layers, bytes };
|
|
60
|
+
return rpcResult(result, layers.flatMap(l => encodedChannelTransferables(l)));
|
|
61
|
+
}
|
|
62
|
+
}
|
package/esm/svg/svgId.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Injective but NOT idempotent — escaping the marker is what buys injectivity,
|
|
6
6
|
* so a second pass re-escapes the `~`s the first one wrote. Apply it exactly
|
|
7
7
|
* once, at the place that emits both the id and the reference to it
|
|
8
|
-
* (`SvgClipRect` and `
|
|
8
|
+
* (`SvgClipRect` and `SvgColorLegend` already do; a hand-rolled `<clipPath>`
|
|
9
9
|
* must). Double-applying is harmless to correctness — the id and its `url()`
|
|
10
10
|
* still agree, since both are derived from one call — but it produces noisy ids
|
|
11
11
|
* for no reason.
|
package/esm/svg/svgId.js
CHANGED
|
@@ -34,7 +34,7 @@ const UNSAFE_ID_CHAR = /[^\w.:-]/g;
|
|
|
34
34
|
* Injective but NOT idempotent — escaping the marker is what buys injectivity,
|
|
35
35
|
* so a second pass re-escapes the `~`s the first one wrote. Apply it exactly
|
|
36
36
|
* once, at the place that emits both the id and the reference to it
|
|
37
|
-
* (`SvgClipRect` and `
|
|
37
|
+
* (`SvgClipRect` and `SvgColorLegend` already do; a hand-rolled `<clipPath>`
|
|
38
38
|
* must). Double-applying is harmless to correctness — the id and its `url()`
|
|
39
39
|
* still agree, since both are derived from one call — but it produces noisy ids
|
|
40
40
|
* for no reason.
|