@vessel-dsp/core 0.6.4 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/README.md +10 -2
  2. package/dist/editor/commands.d.ts +13 -13
  3. package/dist/editor/commands.d.ts.map +1 -1
  4. package/dist/editor/commands.js +44 -29
  5. package/dist/editor/commands.js.map +1 -1
  6. package/dist/editor/factory.d.ts +1 -1
  7. package/dist/editor/factory.d.ts.map +1 -1
  8. package/dist/editor/factory.js +51 -51
  9. package/dist/editor/factory.js.map +1 -1
  10. package/dist/editor/history.d.ts +7 -7
  11. package/dist/editor/history.d.ts.map +1 -1
  12. package/dist/editor/history.js +20 -12
  13. package/dist/editor/history.js.map +1 -1
  14. package/dist/editor/index.d.ts +8 -8
  15. package/dist/editor/index.d.ts.map +1 -1
  16. package/dist/editor/index.js +4 -4
  17. package/dist/editor/index.js.map +1 -1
  18. package/dist/editor/layout.d.ts +1 -1
  19. package/dist/editor/layout.d.ts.map +1 -1
  20. package/dist/editor/layout.js +11 -6
  21. package/dist/editor/layout.js.map +1 -1
  22. package/dist/formats/circuit-json/serializer.d.ts +15 -15
  23. package/dist/formats/circuit-json/serializer.d.ts.map +1 -1
  24. package/dist/formats/circuit-json/serializer.js +486 -394
  25. package/dist/formats/circuit-json/serializer.js.map +1 -1
  26. package/dist/formats/document.d.ts +6 -6
  27. package/dist/formats/document.d.ts.map +1 -1
  28. package/dist/formats/document.js +112 -92
  29. package/dist/formats/document.js.map +1 -1
  30. package/dist/formats/interchange/parser.d.ts +1 -1
  31. package/dist/formats/interchange/parser.d.ts.map +1 -1
  32. package/dist/formats/interchange/parser.js +463 -286
  33. package/dist/formats/interchange/parser.js.map +1 -1
  34. package/dist/formats/interchange/serializer.d.ts +1 -1
  35. package/dist/formats/interchange/serializer.d.ts.map +1 -1
  36. package/dist/formats/interchange/serializer.js +41 -28
  37. package/dist/formats/interchange/serializer.js.map +1 -1
  38. package/dist/formats/ltspice/catalog.d.ts +1 -1
  39. package/dist/formats/ltspice/catalog.d.ts.map +1 -1
  40. package/dist/formats/ltspice/catalog.js +150 -48
  41. package/dist/formats/ltspice/catalog.js.map +1 -1
  42. package/dist/formats/ltspice/encoding.js +12 -40
  43. package/dist/formats/ltspice/encoding.js.map +1 -1
  44. package/dist/formats/ltspice/parser.d.ts +1 -1
  45. package/dist/formats/ltspice/parser.d.ts.map +1 -1
  46. package/dist/formats/ltspice/parser.js +122 -75
  47. package/dist/formats/ltspice/parser.js.map +1 -1
  48. package/dist/formats/ltspice/serializer.d.ts +1 -1
  49. package/dist/formats/ltspice/serializer.d.ts.map +1 -1
  50. package/dist/formats/ltspice/serializer.js +69 -47
  51. package/dist/formats/ltspice/serializer.js.map +1 -1
  52. package/dist/formats/schx/catalog.d.ts +1 -1
  53. package/dist/formats/schx/catalog.d.ts.map +1 -1
  54. package/dist/formats/schx/catalog.js +499 -254
  55. package/dist/formats/schx/catalog.js.map +1 -1
  56. package/dist/formats/schx/parser.d.ts +1 -1
  57. package/dist/formats/schx/parser.d.ts.map +1 -1
  58. package/dist/formats/schx/parser.js +40 -38
  59. package/dist/formats/schx/parser.js.map +1 -1
  60. package/dist/formats/schx/runtime-descriptors.d.ts +1 -1
  61. package/dist/formats/schx/runtime-descriptors.d.ts.map +1 -1
  62. package/dist/formats/schx/runtime-descriptors.js +239 -201
  63. package/dist/formats/schx/runtime-descriptors.js.map +1 -1
  64. package/dist/formats/schx/serializer.d.ts +2 -2
  65. package/dist/formats/schx/serializer.d.ts.map +1 -1
  66. package/dist/formats/schx/serializer.js +106 -106
  67. package/dist/formats/schx/serializer.js.map +1 -1
  68. package/dist/formats/schx/transforms.d.ts +1 -1
  69. package/dist/formats/schx/transforms.d.ts.map +1 -1
  70. package/dist/formats/schx/transforms.js +16 -8
  71. package/dist/formats/schx/transforms.js.map +1 -1
  72. package/dist/formats/spice/parser.d.ts +1 -1
  73. package/dist/formats/spice/parser.d.ts.map +1 -1
  74. package/dist/formats/spice/parser.js +105 -56
  75. package/dist/formats/spice/parser.js.map +1 -1
  76. package/dist/formats/spice/serializer.d.ts +1 -1
  77. package/dist/formats/spice/serializer.js +14 -12
  78. package/dist/formats/spice/serializer.js.map +1 -1
  79. package/dist/index.d.ts +47 -46
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +32 -31
  82. package/dist/index.js.map +1 -1
  83. package/dist/model/connectivity.d.ts +1 -1
  84. package/dist/model/connectivity.d.ts.map +1 -1
  85. package/dist/model/connectivity.js +22 -7
  86. package/dist/model/connectivity.js.map +1 -1
  87. package/dist/model/netlist.d.ts +3 -3
  88. package/dist/model/netlist.d.ts.map +1 -1
  89. package/dist/model/netlist.js +117 -100
  90. package/dist/model/netlist.js.map +1 -1
  91. package/dist/model/properties.d.ts +1 -1
  92. package/dist/model/properties.d.ts.map +1 -1
  93. package/dist/model/properties.js +16 -16
  94. package/dist/model/properties.js.map +1 -1
  95. package/dist/model/quantity.d.ts +1 -1
  96. package/dist/model/quantity.d.ts.map +1 -1
  97. package/dist/model/quantity.js +35 -35
  98. package/dist/model/quantity.js.map +1 -1
  99. package/dist/model/types.d.ts +61 -33
  100. package/dist/model/types.d.ts.map +1 -1
  101. package/dist/model/types.js +1 -1
  102. package/dist/model/types.js.map +1 -1
  103. package/dist/model/validation.d.ts +5 -5
  104. package/dist/model/validation.d.ts.map +1 -1
  105. package/dist/model/validation.js +668 -331
  106. package/dist/model/validation.js.map +1 -1
  107. package/dist/model/wires.d.ts +1 -1
  108. package/dist/model/wires.d.ts.map +1 -1
  109. package/dist/model/wires.js +4 -1
  110. package/dist/model/wires.js.map +1 -1
  111. package/dist/panel/extract.d.ts +2 -2
  112. package/dist/panel/extract.d.ts.map +1 -1
  113. package/dist/panel/extract.js +327 -225
  114. package/dist/panel/extract.js.map +1 -1
  115. package/dist/panel/index.d.ts +7 -7
  116. package/dist/panel/index.d.ts.map +1 -1
  117. package/dist/panel/index.js +5 -5
  118. package/dist/panel/index.js.map +1 -1
  119. package/dist/panel/knobs.d.ts +4 -4
  120. package/dist/panel/knobs.d.ts.map +1 -1
  121. package/dist/panel/knobs.js +1 -1
  122. package/dist/panel/knobs.js.map +1 -1
  123. package/dist/panel/placement.d.ts +1 -1
  124. package/dist/panel/placement.d.ts.map +1 -1
  125. package/dist/panel/placement.js +11 -9
  126. package/dist/panel/placement.js.map +1 -1
  127. package/dist/panel/protocol.d.ts +1 -1
  128. package/dist/panel/protocol.d.ts.map +1 -1
  129. package/dist/panel/protocol.js +32 -23
  130. package/dist/panel/protocol.js.map +1 -1
  131. package/dist/panel/types.d.ts +18 -18
  132. package/dist/panel/types.d.ts.map +1 -1
  133. package/dist/panel/types.js.map +1 -1
  134. package/dist/preview/bounds.d.ts +1 -1
  135. package/dist/preview/bounds.d.ts.map +1 -1
  136. package/dist/preview/bounds.js +3 -3
  137. package/dist/preview/bounds.js.map +1 -1
  138. package/dist/preview/box-layout.d.ts +2 -2
  139. package/dist/preview/box-layout.js.map +1 -1
  140. package/dist/preview/colors.d.ts +1 -1
  141. package/dist/preview/colors.js +35 -35
  142. package/dist/preview/colors.js.map +1 -1
  143. package/dist/preview/hanging.d.ts +1 -1
  144. package/dist/preview/hanging.d.ts.map +1 -1
  145. package/dist/preview/hanging.js +4 -1
  146. package/dist/preview/hanging.js.map +1 -1
  147. package/dist/preview/junctions.d.ts +1 -1
  148. package/dist/preview/junctions.d.ts.map +1 -1
  149. package/dist/preview/junctions.js.map +1 -1
  150. package/dist/preview/label-layout.d.ts.map +1 -1
  151. package/dist/preview/label-layout.js +4 -4
  152. package/dist/preview/label-layout.js.map +1 -1
  153. package/dist/preview/ports.d.ts +1 -1
  154. package/dist/preview/ports.d.ts.map +1 -1
  155. package/dist/preview/ports.js +2 -1
  156. package/dist/preview/ports.js.map +1 -1
  157. package/dist/preview/renderable-wires.d.ts +1 -1
  158. package/dist/preview/renderable-wires.d.ts.map +1 -1
  159. package/dist/preview/renderable-wires.js +3 -1
  160. package/dist/preview/renderable-wires.js.map +1 -1
  161. package/dist/preview/routing.d.ts +1 -1
  162. package/dist/preview/routing.js +1 -1
  163. package/dist/preview/routing.js.map +1 -1
  164. package/dist/preview/snap.d.ts +1 -1
  165. package/dist/preview/snap.d.ts.map +1 -1
  166. package/dist/preview/snap.js +11 -3
  167. package/dist/preview/snap.js.map +1 -1
  168. package/dist/preview/symbols/svg-content.d.ts.map +1 -1
  169. package/dist/preview/symbols/svg-content.js +200 -50
  170. package/dist/preview/symbols/svg-content.js.map +1 -1
  171. package/dist/preview/symbols.d.ts +2 -2
  172. package/dist/preview/symbols.d.ts.map +1 -1
  173. package/dist/preview/symbols.js +100 -97
  174. package/dist/preview/symbols.js.map +1 -1
  175. package/dist/preview/wire-chains.d.ts +1 -1
  176. package/dist/preview/wire-chains.d.ts.map +1 -1
  177. package/dist/preview/wire-chains.js.map +1 -1
  178. package/dist/profiles.d.ts +600 -0
  179. package/dist/profiles.d.ts.map +1 -0
  180. package/dist/profiles.js +118 -0
  181. package/dist/profiles.js.map +1 -0
  182. package/package.json +54 -54
@@ -1,13 +1,48 @@
1
- import { isParsedQuantity, propertyNumericValue, propertyStringValue } from '../model/properties.js';
2
- import { buildKnobSteps, snapKnobPosition } from './knobs.js';
1
+ import { isParsedQuantity, propertyNumericValue, propertyStringValue, } from "../model/properties.js";
2
+ import { buildKnobSteps, snapKnobPosition } from "./knobs.js";
3
3
  const RUNTIME_CONTINUOUS_CONTROL_SPECS = [
4
- { key: 'time', controlProperty: 'TimeControl', wipeProperty: 'TimeControlWipe', sweepProperty: 'TimeControlSweep' },
5
- { key: 'feedback', controlProperty: 'FeedbackControl', wipeProperty: 'FeedbackControlWipe', sweepProperty: 'FeedbackControlSweep' },
6
- { key: 'mix', controlProperty: 'MixControl', wipeProperty: 'MixControlWipe', sweepProperty: 'MixControlSweep' },
7
- { key: 'level', controlProperty: 'LevelControl', wipeProperty: 'LevelControlWipe', sweepProperty: 'LevelControlSweep' },
8
- { key: 'tone', controlProperty: 'ToneControl', wipeProperty: 'ToneControlWipe', sweepProperty: 'ToneControlSweep' },
9
- { key: 'mod-rate', controlProperty: 'ModRateControl', wipeProperty: 'ModRateControlWipe', sweepProperty: 'ModRateControlSweep' },
10
- { key: 'mod-depth', controlProperty: 'ModDepthControl', wipeProperty: 'ModDepthControlWipe', sweepProperty: 'ModDepthControlSweep' },
4
+ {
5
+ key: "time",
6
+ controlProperty: "TimeControl",
7
+ wipeProperty: "TimeControlWipe",
8
+ sweepProperty: "TimeControlSweep",
9
+ },
10
+ {
11
+ key: "feedback",
12
+ controlProperty: "FeedbackControl",
13
+ wipeProperty: "FeedbackControlWipe",
14
+ sweepProperty: "FeedbackControlSweep",
15
+ },
16
+ {
17
+ key: "mix",
18
+ controlProperty: "MixControl",
19
+ wipeProperty: "MixControlWipe",
20
+ sweepProperty: "MixControlSweep",
21
+ },
22
+ {
23
+ key: "level",
24
+ controlProperty: "LevelControl",
25
+ wipeProperty: "LevelControlWipe",
26
+ sweepProperty: "LevelControlSweep",
27
+ },
28
+ {
29
+ key: "tone",
30
+ controlProperty: "ToneControl",
31
+ wipeProperty: "ToneControlWipe",
32
+ sweepProperty: "ToneControlSweep",
33
+ },
34
+ {
35
+ key: "mod-rate",
36
+ controlProperty: "ModRateControl",
37
+ wipeProperty: "ModRateControlWipe",
38
+ sweepProperty: "ModRateControlSweep",
39
+ },
40
+ {
41
+ key: "mod-depth",
42
+ controlProperty: "ModDepthControl",
43
+ wipeProperty: "ModDepthControlWipe",
44
+ sweepProperty: "ModDepthControlSweep",
45
+ },
11
46
  ];
12
47
  // extractPanel inspects a CircuitDocument and emits the typed Panel descriptor
13
48
  // that drives the runtime control surface. It's a pure read over the existing
@@ -20,7 +55,7 @@ export function extractPanel(doc) {
20
55
  const jacks = [];
21
56
  for (const component of doc.components) {
22
57
  switch (component.kind) {
23
- case 'variable-resistor': {
58
+ case "variable-resistor": {
24
59
  if (!isVariableResistorControl(component)) {
25
60
  break;
26
61
  }
@@ -32,7 +67,7 @@ export function extractPanel(doc) {
32
67
  }
33
68
  break;
34
69
  }
35
- case 'potentiometer': {
70
+ case "potentiometer": {
36
71
  if (isSliderControl(component)) {
37
72
  sliders.push(toSlider(component));
38
73
  }
@@ -41,15 +76,15 @@ export function extractPanel(doc) {
41
76
  }
42
77
  break;
43
78
  }
44
- case 'switch': {
79
+ case "switch": {
45
80
  switches.push(toSwitch(component));
46
81
  break;
47
82
  }
48
- case 'led': {
83
+ case "led": {
49
84
  leds.push(toLed(component));
50
85
  break;
51
86
  }
52
- case 'jack': {
87
+ case "jack": {
53
88
  jacks.push(toJack(component));
54
89
  break;
55
90
  }
@@ -86,7 +121,7 @@ export function extractDeviceInterface(doc) {
86
121
  for (const control of doc.deviceInterface?.controls ?? []) {
87
122
  controls.set(control.id, {
88
123
  ...control,
89
- provenance: 'vdsp-declared',
124
+ provenance: "vdsp-declared",
90
125
  });
91
126
  }
92
127
  for (const inferred of inferredControls) {
@@ -102,11 +137,11 @@ export function extractDeviceInterface(doc) {
102
137
  });
103
138
  continue;
104
139
  }
105
- if (declared.binding !== undefined
106
- && inferred.binding !== undefined
107
- && bindingSignature(declared.binding) !== bindingSignature(inferred.binding)) {
140
+ if (declared.binding !== undefined &&
141
+ inferred.binding !== undefined &&
142
+ bindingSignature(declared.binding) !== bindingSignature(inferred.binding)) {
108
143
  diagnostics.push({
109
- code: 'device-interface-inferred-binding-conflict',
144
+ code: "device-interface-inferred-binding-conflict",
110
145
  message: `Declared device interface control "${declared.id}" conflicts with inferred binding`,
111
146
  componentId: declared.id,
112
147
  });
@@ -137,8 +172,12 @@ function resolveControlGroupMemberships(groups, controls) {
137
172
  group,
138
173
  control,
139
174
  ...(member.order === undefined ? {} : { order: member.order }),
140
- ...(member.appliesWhen === undefined ? {} : { appliesWhen: member.appliesWhen }),
141
- ...(member.description === undefined ? {} : { description: member.description }),
175
+ ...(member.appliesWhen === undefined
176
+ ? {}
177
+ : { appliesWhen: member.appliesWhen }),
178
+ ...(member.description === undefined
179
+ ? {}
180
+ : { description: member.description }),
142
181
  });
143
182
  }
144
183
  }
@@ -147,15 +186,20 @@ function resolveControlGroupMemberships(groups, controls) {
147
186
  continue;
148
187
  }
149
188
  const group = groupsById.get(control.groupId);
150
- if (group === undefined || explicitMemberships.has(`${group.id}:${control.id}`)) {
189
+ if (group === undefined ||
190
+ explicitMemberships.has(`${group.id}:${control.id}`)) {
151
191
  continue;
152
192
  }
153
193
  memberships.push({
154
194
  group,
155
195
  control,
156
196
  ...(control.order === undefined ? {} : { order: control.order }),
157
- ...(control.appliesWhen === undefined ? {} : { appliesWhen: control.appliesWhen }),
158
- ...(control.description === undefined ? {} : { description: control.description }),
197
+ ...(control.appliesWhen === undefined
198
+ ? {}
199
+ : { appliesWhen: control.appliesWhen }),
200
+ ...(control.description === undefined
201
+ ? {}
202
+ : { description: control.description }),
159
203
  });
160
204
  }
161
205
  return memberships;
@@ -175,7 +219,7 @@ function inferDeviceInterfaceControls(doc, panel) {
175
219
  controls.push({
176
220
  id: knob.id,
177
221
  label: knob.name,
178
- kind: 'knob',
222
+ kind: "knob",
179
223
  role: roleFromControlId(knob.id),
180
224
  binding: {
181
225
  componentId,
@@ -190,21 +234,21 @@ function inferDeviceInterfaceControls(doc, panel) {
190
234
  controls.push({
191
235
  id: slider.id,
192
236
  label: slider.name,
193
- kind: 'slider',
237
+ kind: "slider",
194
238
  role: roleFromControlId(slider.id),
195
239
  binding: {
196
240
  componentId: componentIdFromControlId(slider.id),
197
241
  controlId: slider.id,
198
242
  controlName: slider.name,
199
243
  },
200
- provenance: 'source-inferred',
244
+ provenance: "source-inferred",
201
245
  });
202
246
  }
203
247
  for (const switchControl of panel.switches) {
204
248
  controls.push({
205
249
  id: switchControl.id,
206
250
  label: switchControl.name,
207
- kind: 'switch',
251
+ kind: "switch",
208
252
  role: roleFromControlId(switchControl.id),
209
253
  binding: {
210
254
  componentId: componentIdFromControlId(switchControl.id),
@@ -218,14 +262,14 @@ function inferDeviceInterfaceControls(doc, panel) {
218
262
  controls.push({
219
263
  id: led.id,
220
264
  label: led.name,
221
- kind: 'led',
222
- role: 'indicator',
265
+ kind: "led",
266
+ role: "indicator",
223
267
  binding: {
224
268
  componentId: componentIdFromControlId(led.id),
225
269
  controlId: led.id,
226
270
  controlName: led.name,
227
271
  },
228
- provenance: 'source-inferred',
272
+ provenance: "source-inferred",
229
273
  });
230
274
  }
231
275
  for (const jack of panel.jacks) {
@@ -234,11 +278,11 @@ function inferDeviceInterfaceControls(doc, panel) {
234
278
  controls.push({
235
279
  id: jack.id,
236
280
  label: jack.name,
237
- kind: 'jack',
281
+ kind: "jack",
238
282
  role: jack.controlRole ?? jack.role,
239
283
  ...(binding === undefined ? {} : { binding }),
240
284
  provenance: controlInterfaceIds.has(jack.id)
241
- ? 'control-interface-declared'
285
+ ? "control-interface-declared"
242
286
  : provenanceForComponentControl(doc, componentId),
243
287
  });
244
288
  }
@@ -248,12 +292,12 @@ function deviceBindingForJack(jack, componentId) {
248
292
  if (jack.binding !== undefined) {
249
293
  return deviceBindingFromControlInterfaceBinding(jack.binding, componentId);
250
294
  }
251
- if (jack.id.endsWith(':tempo-tap')) {
295
+ if (jack.id.endsWith(":tempo-tap")) {
252
296
  return {
253
297
  componentId,
254
298
  controlId: jack.id,
255
299
  controlName: jack.name,
256
- property: 'TempoTapControl',
300
+ property: "TempoTapControl",
257
301
  };
258
302
  }
259
303
  if (jack.sourceComponentId !== undefined || jack.id === componentId) {
@@ -272,23 +316,27 @@ function deviceBindingFromControlInterfaceBinding(binding, fallbackComponentId)
272
316
  const componentId = binding.sourceComponentId ?? fallbackComponentId;
273
317
  return {
274
318
  componentId,
275
- ...(binding.controlId === undefined ? {} : { controlId: binding.controlId }),
276
- ...(binding.controlName === undefined ? {} : { controlName: binding.controlName }),
319
+ ...(binding.controlId === undefined
320
+ ? {}
321
+ : { controlId: binding.controlId }),
322
+ ...(binding.controlName === undefined
323
+ ? {}
324
+ : { controlName: binding.controlName }),
277
325
  ...(binding.property === undefined ? {} : { property: binding.property }),
278
326
  };
279
327
  }
280
328
  function provenanceForComponentControl(doc, componentId) {
281
329
  const component = doc.components.find((candidate) => candidate.id === componentId);
282
330
  return component !== undefined && isRuntimeDescriptor(component)
283
- ? 'runtime-descriptor-inferred'
284
- : 'source-inferred';
331
+ ? "runtime-descriptor-inferred"
332
+ : "source-inferred";
285
333
  }
286
334
  function componentIdFromControlId(id) {
287
- const separator = id.indexOf(':');
335
+ const separator = id.indexOf(":");
288
336
  return separator <= 0 ? id : id.slice(0, separator);
289
337
  }
290
338
  function roleFromControlId(id) {
291
- const separator = id.indexOf(':');
339
+ const separator = id.indexOf(":");
292
340
  const raw = separator >= 0 ? id.slice(separator + 1) : id;
293
341
  return normalizeToken(raw);
294
342
  }
@@ -299,25 +347,25 @@ function runtimeControlProperty(id) {
299
347
  return spec.controlProperty;
300
348
  }
301
349
  }
302
- if (key === 'mode') {
303
- return 'ModeControl';
350
+ if (key === "mode") {
351
+ return "ModeControl";
304
352
  }
305
- if (key === 'tempo-tap') {
306
- return 'TempoTapControl';
353
+ if (key === "tempo-tap") {
354
+ return "TempoTapControl";
307
355
  }
308
- if (key === 'direct-out') {
309
- return 'DirectOutputJack';
356
+ if (key === "direct-out") {
357
+ return "DirectOutputJack";
310
358
  }
311
359
  return undefined;
312
360
  }
313
361
  function bindingSignature(binding) {
314
362
  return [
315
363
  binding.componentId,
316
- binding.controlId ?? '',
317
- binding.controlName ?? '',
318
- binding.property ?? '',
319
- binding.externalInterfaceId ?? '',
320
- ].join(':');
364
+ binding.controlId ?? "",
365
+ binding.controlName ?? "",
366
+ binding.property ?? "",
367
+ binding.externalInterfaceId ?? "",
368
+ ].join(":");
321
369
  }
322
370
  function applyControlInterfaces(controlInterfaces, jacks) {
323
371
  for (const controlInterface of controlInterfaces ?? []) {
@@ -347,70 +395,90 @@ function toControlInterfaceJack(controlInterface) {
347
395
  ...(sourceComponentId === undefined ? {} : { sourceComponentId }),
348
396
  ...(controlRole === undefined ? {} : { controlRole }),
349
397
  ...(interfaceName === undefined ? {} : { interface: interfaceName }),
350
- ...(controlInterface.connector === undefined ? {} : { connector: controlInterface.connector }),
351
- ...(controlInterface.assignmentHint === undefined ? {} : { assignmentHint: controlInterface.assignmentHint }),
352
- ...(controlInterface.polarity === undefined ? {} : { polarity: controlInterface.polarity }),
353
- ...(controlInterface.binding === undefined ? {} : { binding: controlInterface.binding }),
354
- ...(controlInterface.description === undefined ? {} : { description: controlInterface.description }),
398
+ ...(controlInterface.connector === undefined
399
+ ? {}
400
+ : { connector: controlInterface.connector }),
401
+ ...(controlInterface.assignmentHint === undefined
402
+ ? {}
403
+ : { assignmentHint: controlInterface.assignmentHint }),
404
+ ...(controlInterface.polarity === undefined
405
+ ? {}
406
+ : { polarity: controlInterface.polarity }),
407
+ ...(controlInterface.binding === undefined
408
+ ? {}
409
+ : { binding: controlInterface.binding }),
410
+ ...(controlInterface.description === undefined
411
+ ? {}
412
+ : { description: controlInterface.description }),
355
413
  };
356
414
  }
357
415
  function jackRoleForControlInterface(controlInterface) {
358
416
  switch (controlInterface.role) {
359
- case 'tempo-tap':
360
- return 'tempo-tap';
361
- case 'expression':
362
- return 'expression';
363
- case 'external-control':
364
- case 'trigger':
365
- case 'reset':
366
- case 'sampler-trigger':
367
- return 'external-control';
368
- case 'unknown':
369
- return 'unknown';
417
+ case "tempo-tap":
418
+ return "tempo-tap";
419
+ case "expression":
420
+ return "expression";
421
+ case "external-control":
422
+ case "trigger":
423
+ case "reset":
424
+ case "sampler-trigger":
425
+ return "external-control";
426
+ case "unknown":
427
+ return "unknown";
370
428
  }
371
429
  }
372
430
  function defaultControlRole(controlInterface) {
373
- return controlInterface.role === 'unknown' || controlInterface.role === 'external-control'
431
+ return controlInterface.role === "unknown" ||
432
+ controlInterface.role === "external-control"
374
433
  ? undefined
375
434
  : controlInterface.role;
376
435
  }
377
436
  function defaultInterfaceName(controlInterface) {
378
- if (controlInterface.role === 'tempo-tap') {
379
- return 'tap-tempo';
437
+ if (controlInterface.role === "tempo-tap") {
438
+ return "tap-tempo";
380
439
  }
381
- if (controlInterface.role === 'unknown') {
440
+ if (controlInterface.role === "unknown") {
382
441
  return undefined;
383
442
  }
384
- return 'external-control-input';
443
+ return "external-control-input";
385
444
  }
386
445
  function toKnob(component) {
387
- const taper = resolveTaper(propertyString(component, 'Sweep') ?? propertyString(component, 'Taper'));
388
- const stepLabels = parseStepLabels(propertyStringAny(component, ['StepLabels', 'Steps']));
389
- const explicitStepCount = parseStepCount(propertyStringAny(component, ['StepCount', 'Detents', 'Positions', 'Steps']));
390
- const steps = buildKnobSteps(stepLabels.length >= 2 ? stepLabels.length : explicitStepCount ?? 0, stepLabels);
446
+ const taper = resolveTaper(propertyString(component, "Sweep") ?? propertyString(component, "Taper"));
447
+ const stepLabels = parseStepLabels(propertyStringAny(component, ["StepLabels", "Steps"]));
448
+ const explicitStepCount = parseStepCount(propertyStringAny(component, [
449
+ "StepCount",
450
+ "Detents",
451
+ "Positions",
452
+ "Steps",
453
+ ]));
454
+ const steps = buildKnobSteps(stepLabels.length >= 2 ? stepLabels.length : (explicitStepCount ?? 0), stepLabels);
391
455
  const rawDefaultPosition = clamp01(parseNumeric(component.properties.Wipe) ?? 0.5);
392
- const defaultPosition = steps === undefined ? rawDefaultPosition : snapKnobPosition({ steps }, rawDefaultPosition);
393
- const resistance = quantityProperty(component, 'Resistance');
394
- const gangGroup = propertyString(component, 'Group') ?? undefined;
395
- const description = propertyString(component, 'Description') ?? undefined;
456
+ const defaultPosition = steps === undefined
457
+ ? rawDefaultPosition
458
+ : snapKnobPosition({ steps }, rawDefaultPosition);
459
+ const resistance = quantityProperty(component, "Resistance");
460
+ const gangGroup = propertyString(component, "Group") ?? undefined;
461
+ const description = propertyString(component, "Description") ?? undefined;
396
462
  return {
397
463
  id: component.id,
398
464
  name: component.name,
399
465
  taper,
400
- controlMode: steps === undefined ? 'continuous' : 'stepped',
466
+ controlMode: steps === undefined ? "continuous" : "stepped",
401
467
  defaultPosition,
402
468
  ...(steps !== undefined ? { steps } : {}),
403
469
  ...(resistance !== undefined ? { resistance } : {}),
404
470
  ...(gangGroup !== undefined && gangGroup.length > 0 ? { gangGroup } : {}),
405
- ...(description !== undefined && description.length > 0 ? { description } : {}),
471
+ ...(description !== undefined && description.length > 0
472
+ ? { description }
473
+ : {}),
406
474
  };
407
475
  }
408
476
  function toSlider(component) {
409
477
  const defaultPosition = clamp01(parseNumeric(component.properties.Wipe) ?? 0.5);
410
- const orientation = resolveSliderOrientation(propertyStringAny(component, ['Orientation', 'SliderOrientation']));
478
+ const orientation = resolveSliderOrientation(propertyStringAny(component, ["Orientation", "SliderOrientation"]));
411
479
  const range = sliderRange(component);
412
- const gangGroup = propertyString(component, 'Group') ?? undefined;
413
- const description = propertyString(component, 'Description') ?? undefined;
480
+ const gangGroup = propertyString(component, "Group") ?? undefined;
481
+ const description = propertyString(component, "Description") ?? undefined;
414
482
  return {
415
483
  id: component.id,
416
484
  name: component.name,
@@ -418,16 +486,18 @@ function toSlider(component) {
418
486
  orientation,
419
487
  ...(range !== undefined ? { range } : {}),
420
488
  ...(gangGroup !== undefined && gangGroup.length > 0 ? { gangGroup } : {}),
421
- ...(description !== undefined && description.length > 0 ? { description } : {}),
489
+ ...(description !== undefined && description.length > 0
490
+ ? { description }
491
+ : {}),
422
492
  };
423
493
  }
424
494
  function toSwitch(component) {
425
495
  const switchKind = resolveSwitchKind(component);
426
496
  const { poles, positions } = switchGeometry(switchKind);
427
497
  const defaultPosition = clampInt(parseNumeric(component.properties.Position) ?? 0, 0, positions - 1);
428
- const gangGroup = propertyString(component, 'Group') ?? undefined;
429
- const partNumber = propertyString(component, 'PartNumber') ?? undefined;
430
- const description = propertyString(component, 'Description') ?? undefined;
498
+ const gangGroup = propertyString(component, "Group") ?? undefined;
499
+ const partNumber = propertyString(component, "PartNumber") ?? undefined;
500
+ const description = propertyString(component, "Description") ?? undefined;
431
501
  return {
432
502
  id: component.id,
433
503
  name: component.name,
@@ -436,30 +506,39 @@ function toSwitch(component) {
436
506
  positions,
437
507
  defaultPosition,
438
508
  ...(gangGroup !== undefined && gangGroup.length > 0 ? { gangGroup } : {}),
439
- ...(partNumber !== undefined && partNumber.length > 0 ? { partNumber } : {}),
440
- ...(description !== undefined && description.length > 0 ? { description } : {}),
509
+ ...(partNumber !== undefined && partNumber.length > 0
510
+ ? { partNumber }
511
+ : {}),
512
+ ...(description !== undefined && description.length > 0
513
+ ? { description }
514
+ : {}),
441
515
  };
442
516
  }
443
517
  function toLed(component) {
444
- const color = propertyString(component, 'Color') ?? inferLedColor(component);
445
- const partNumber = propertyString(component, 'PartNumber') ?? undefined;
446
- const description = propertyString(component, 'Description') ?? undefined;
518
+ const color = propertyString(component, "Color") ?? inferLedColor(component);
519
+ const partNumber = propertyString(component, "PartNumber") ?? undefined;
520
+ const description = propertyString(component, "Description") ?? undefined;
447
521
  return {
448
522
  id: component.id,
449
523
  name: component.name,
450
524
  ...(color !== undefined ? { color } : {}),
451
- ...(partNumber !== undefined && partNumber.length > 0 ? { partNumber } : {}),
452
- ...(description !== undefined && description.length > 0 ? { description } : {}),
525
+ ...(partNumber !== undefined && partNumber.length > 0
526
+ ? { partNumber }
527
+ : {}),
528
+ ...(description !== undefined && description.length > 0
529
+ ? { description }
530
+ : {}),
453
531
  };
454
532
  }
455
533
  function toJack(component) {
456
534
  const role = resolveJackRole(component);
457
- const name = nonEmptyString(propertyStringAny(component, ['JackLabel', 'Label'])) ?? component.name;
458
- const audioRole = nonEmptyString(propertyString(component, 'AudioRole'));
459
- const impedance = quantityProperty(component, 'Impedance');
460
- const controlRole = nonEmptyString(propertyString(component, 'ControlRole'));
461
- const interfaceName = nonEmptyString(propertyString(component, 'Interface'));
462
- const description = propertyString(component, 'Description') ?? undefined;
535
+ const name = nonEmptyString(propertyStringAny(component, ["JackLabel", "Label"])) ??
536
+ component.name;
537
+ const audioRole = nonEmptyString(propertyString(component, "AudioRole"));
538
+ const impedance = quantityProperty(component, "Impedance");
539
+ const controlRole = nonEmptyString(propertyString(component, "ControlRole"));
540
+ const interfaceName = nonEmptyString(propertyString(component, "Interface"));
541
+ const description = propertyString(component, "Description") ?? undefined;
463
542
  const sourceTypeName = component.sourceTypeName ?? undefined;
464
543
  return {
465
544
  id: component.id,
@@ -470,7 +549,9 @@ function toJack(component) {
470
549
  ...(sourceTypeName !== undefined ? { sourceTypeName } : {}),
471
550
  ...(controlRole !== undefined ? { controlRole } : {}),
472
551
  ...(interfaceName !== undefined ? { interface: interfaceName } : {}),
473
- ...(description !== undefined && description.length > 0 ? { description } : {}),
552
+ ...(description !== undefined && description.length > 0
553
+ ? { description }
554
+ : {}),
474
555
  };
475
556
  }
476
557
  function runtimeDescriptorKnobs(component) {
@@ -484,7 +565,7 @@ function runtimeDescriptorKnobs(component) {
484
565
  id: `${component.id}:${spec.key}`,
485
566
  name,
486
567
  taper: resolveTaper(propertyString(component, spec.sweepProperty)),
487
- controlMode: 'continuous',
568
+ controlMode: "continuous",
488
569
  defaultPosition: clamp01(parseNumeric(component.properties[spec.wipeProperty]) ?? 0.5),
489
570
  });
490
571
  }
@@ -495,102 +576,120 @@ function runtimeDescriptorKnobs(component) {
495
576
  return knobs;
496
577
  }
497
578
  function runtimeDescriptorMode(component) {
498
- const name = nonEmptyString(propertyString(component, 'ModeControl'));
499
- const labels = parseStepLabels(propertyStringAny(component, ['ModeLabels', 'ModeOptions']));
500
- const explicitStepCount = parseStepCount(propertyStringAny(component, ['ModeStepCount', 'ModeSteps', 'ModeCount']));
501
- const steps = buildKnobSteps(labels.length >= 2 ? labels.length : explicitStepCount ?? 0, labels);
579
+ const name = nonEmptyString(propertyString(component, "ModeControl"));
580
+ const labels = parseStepLabels(propertyStringAny(component, ["ModeLabels", "ModeOptions"]));
581
+ const explicitStepCount = parseStepCount(propertyStringAny(component, ["ModeStepCount", "ModeSteps", "ModeCount"]));
582
+ const steps = buildKnobSteps(labels.length >= 2 ? labels.length : (explicitStepCount ?? 0), labels);
502
583
  if (name === undefined || steps === undefined) {
503
584
  return undefined;
504
585
  }
505
586
  return {
506
587
  id: `${component.id}:mode`,
507
588
  name,
508
- taper: 'unknown',
509
- controlMode: 'stepped',
510
- defaultPosition: runtimeModeDefaultPosition(steps, parseNumericAny(component, ['ModeControlWipe', 'ModeDefaultIndex', 'ModeIndex'])),
589
+ taper: "unknown",
590
+ controlMode: "stepped",
591
+ defaultPosition: runtimeModeDefaultPosition(steps, parseNumericAny(component, [
592
+ "ModeControlWipe",
593
+ "ModeDefaultIndex",
594
+ "ModeIndex",
595
+ ])),
511
596
  steps,
512
597
  };
513
598
  }
514
599
  function runtimeDescriptorTempoTap(component) {
515
- const name = nonEmptyString(propertyStringAny(component, ['TempoTapControl', 'TapTempoControl', 'TempoControl']));
600
+ const name = nonEmptyString(propertyStringAny(component, [
601
+ "TempoTapControl",
602
+ "TapTempoControl",
603
+ "TempoControl",
604
+ ]));
516
605
  if (name === undefined) {
517
606
  return undefined;
518
607
  }
519
608
  const sourceTypeName = component.sourceTypeName ?? undefined;
520
- const assignmentHint = 'momentary';
609
+ const assignmentHint = "momentary";
521
610
  return {
522
611
  id: `${component.id}:tempo-tap`,
523
612
  name,
524
- role: 'tempo-tap',
613
+ role: "tempo-tap",
525
614
  sourceComponentId: component.id,
526
- controlRole: 'tempo-tap',
527
- interface: 'tap-tempo',
615
+ controlRole: "tempo-tap",
616
+ interface: "tap-tempo",
528
617
  assignmentHint,
529
618
  ...(sourceTypeName !== undefined ? { sourceTypeName } : {}),
530
619
  };
531
620
  }
532
621
  function runtimeDescriptorDirectOut(component) {
533
622
  const name = nonEmptyString(propertyStringAny(component, [
534
- 'DirectOutputJack',
535
- 'DirectOutJack',
536
- 'DirectOutputControl',
537
- 'DirectOutControl',
623
+ "DirectOutputJack",
624
+ "DirectOutJack",
625
+ "DirectOutputControl",
626
+ "DirectOutControl",
538
627
  ]));
539
628
  if (name === undefined) {
540
629
  return undefined;
541
630
  }
542
631
  const sourceTypeName = component.sourceTypeName ?? undefined;
543
632
  const description = nonEmptyString(propertyStringAny(component, [
544
- 'DirectOutputRuntimeBoundary',
545
- 'DirectOutputDescription',
546
- 'DirectOutDescription',
633
+ "DirectOutputRuntimeBoundary",
634
+ "DirectOutputDescription",
635
+ "DirectOutDescription",
547
636
  ]));
548
637
  const controlId = `${component.id}:direct-out`;
549
638
  return {
550
639
  id: controlId,
551
640
  name,
552
- role: 'direct-output',
641
+ role: "direct-output",
553
642
  sourceComponentId: component.id,
554
- controlRole: 'direct-output',
555
- interface: 'audio-output',
643
+ controlRole: "direct-output",
644
+ interface: "audio-output",
556
645
  binding: {
557
646
  sourceComponentId: component.id,
558
647
  controlId,
559
648
  controlName: name,
560
- property: 'DirectOutputJack',
649
+ property: "DirectOutputJack",
561
650
  },
562
651
  ...(sourceTypeName !== undefined ? { sourceTypeName } : {}),
563
652
  ...(description === undefined ? {} : { description }),
564
653
  };
565
654
  }
566
655
  function isSliderControl(component) {
567
- const style = propertyStringAny(component, ['ControlStyle', 'ControlType', 'PanelControl', 'UiControl', 'Style']);
656
+ const style = propertyStringAny(component, [
657
+ "ControlStyle",
658
+ "ControlType",
659
+ "PanelControl",
660
+ "UiControl",
661
+ "Style",
662
+ ]);
568
663
  if (style === null) {
569
664
  return false;
570
665
  }
571
666
  const lower = style.toLowerCase();
572
- return lower.includes('slider') || lower.includes('fader');
667
+ return lower.includes("slider") || lower.includes("fader");
573
668
  }
574
669
  function isVariableResistorControl(component) {
575
- return component.properties.Wipe !== undefined
576
- || component.properties.Sweep !== undefined
577
- || component.properties.Taper !== undefined
578
- || isSliderControl(component);
670
+ return (component.properties.Wipe !== undefined ||
671
+ component.properties.Sweep !== undefined ||
672
+ component.properties.Taper !== undefined ||
673
+ isSliderControl(component));
579
674
  }
580
675
  function resolveSliderOrientation(value) {
581
- if (value?.toLowerCase().includes('horizontal')) {
582
- return 'horizontal';
676
+ if (value?.toLowerCase().includes("horizontal")) {
677
+ return "horizontal";
583
678
  }
584
- return 'vertical';
679
+ return "vertical";
585
680
  }
586
681
  function sliderRange(component) {
587
- const min = parseNumericAny(component, ['RangeMin', 'Min', 'Minimum']);
588
- const max = parseNumericAny(component, ['RangeMax', 'Max', 'Maximum']);
682
+ const min = parseNumericAny(component, ["RangeMin", "Min", "Minimum"]);
683
+ const max = parseNumericAny(component, ["RangeMax", "Max", "Maximum"]);
589
684
  if (min === undefined || max === undefined || min >= max) {
590
685
  return undefined;
591
686
  }
592
- const unit = propertyStringAny(component, ['Unit', 'RangeUnit']) ?? undefined;
593
- const center = parseNumericAny(component, ['Center', 'CenterValue', 'RangeCenter']);
687
+ const unit = propertyStringAny(component, ["Unit", "RangeUnit"]) ?? undefined;
688
+ const center = parseNumericAny(component, [
689
+ "Center",
690
+ "CenterValue",
691
+ "RangeCenter",
692
+ ]);
594
693
  return {
595
694
  min,
596
695
  max,
@@ -600,19 +699,19 @@ function sliderRange(component) {
600
699
  }
601
700
  function resolveTaper(value) {
602
701
  if (value === null || value === undefined) {
603
- return 'unknown';
702
+ return "unknown";
604
703
  }
605
704
  const lower = value.toLowerCase();
606
- if (lower.includes('log') && lower.includes('rev')) {
607
- return 'reverse-log';
705
+ if (lower.includes("log") && lower.includes("rev")) {
706
+ return "reverse-log";
608
707
  }
609
- if (lower.includes('log') || lower.includes('audio')) {
610
- return 'log';
708
+ if (lower.includes("log") || lower.includes("audio")) {
709
+ return "log";
611
710
  }
612
- if (lower.includes('lin')) {
613
- return 'linear';
711
+ if (lower.includes("lin")) {
712
+ return "linear";
614
713
  }
615
- return 'unknown';
714
+ return "unknown";
616
715
  }
617
716
  function resolveSwitchKind(component) {
618
717
  const short = shortType(component.sourceTypeName);
@@ -620,47 +719,47 @@ function resolveSwitchKind(component) {
620
719
  return inferFromTerminals(component.terminals.length);
621
720
  }
622
721
  const upper = short.toUpperCase();
623
- if (upper === 'SPDT')
624
- return 'spdt';
625
- if (upper === 'SP3T')
626
- return 'sp3t';
627
- if (upper === 'SP4T')
628
- return 'sp4t';
629
- if (upper === '3PDT')
630
- return '3pdt';
631
- if (upper === 'TOGGLE')
632
- return 'toggle';
633
- if (upper === 'ROTARY')
634
- return 'rotary';
635
- if (upper === 'SWITCH')
636
- return 'spst';
722
+ if (upper === "SPDT")
723
+ return "spdt";
724
+ if (upper === "SP3T")
725
+ return "sp3t";
726
+ if (upper === "SP4T")
727
+ return "sp4t";
728
+ if (upper === "3PDT")
729
+ return "3pdt";
730
+ if (upper === "TOGGLE")
731
+ return "toggle";
732
+ if (upper === "ROTARY")
733
+ return "rotary";
734
+ if (upper === "SWITCH")
735
+ return "spst";
637
736
  return inferFromTerminals(component.terminals.length);
638
737
  }
639
738
  function inferFromTerminals(count) {
640
739
  if (count <= 2)
641
- return 'spst';
740
+ return "spst";
642
741
  if (count === 3)
643
- return 'spdt';
742
+ return "spdt";
644
743
  if (count === 9)
645
- return '3pdt';
646
- return 'unknown';
744
+ return "3pdt";
745
+ return "unknown";
647
746
  }
648
747
  function switchGeometry(kind) {
649
748
  switch (kind) {
650
- case 'spst':
651
- case 'toggle':
749
+ case "spst":
750
+ case "toggle":
652
751
  return { poles: 1, positions: 2 };
653
- case 'spdt':
752
+ case "spdt":
654
753
  return { poles: 1, positions: 2 };
655
- case 'sp3t':
754
+ case "sp3t":
656
755
  return { poles: 1, positions: 3 };
657
- case 'sp4t':
756
+ case "sp4t":
658
757
  return { poles: 1, positions: 4 };
659
- case '3pdt':
758
+ case "3pdt":
660
759
  return { poles: 3, positions: 2 };
661
- case 'rotary':
760
+ case "rotary":
662
761
  return { poles: 1, positions: 6 };
663
- case 'unknown':
762
+ case "unknown":
664
763
  return { poles: 1, positions: 2 };
665
764
  }
666
765
  }
@@ -671,23 +770,23 @@ function resolveJackRole(component) {
671
770
  }
672
771
  const short = shortType(component.sourceTypeName);
673
772
  if (short === null) {
674
- return 'unknown';
773
+ return "unknown";
675
774
  }
676
775
  const upper = short.toUpperCase();
677
- if (upper === 'INPUT' || upper === 'INPUTJACK')
678
- return 'input';
679
- if (upper === 'SPEAKER' || upper === 'OUTPUTJACK')
680
- return 'output';
681
- if (upper === 'SEND')
682
- return 'send';
683
- if (upper === 'RETURN')
684
- return 'return';
685
- if (upper === 'EXPRESSION' || upper === 'EXP')
686
- return 'expression';
687
- return 'unknown';
776
+ if (upper === "INPUT" || upper === "INPUTJACK")
777
+ return "input";
778
+ if (upper === "SPEAKER" || upper === "OUTPUTJACK")
779
+ return "output";
780
+ if (upper === "SEND")
781
+ return "send";
782
+ if (upper === "RETURN")
783
+ return "return";
784
+ if (upper === "EXPRESSION" || upper === "EXP")
785
+ return "expression";
786
+ return "unknown";
688
787
  }
689
788
  function resolveSemanticJackRole(component) {
690
- const semanticProperties = ['Role', 'ControlRole', 'Interface'];
789
+ const semanticProperties = ["Role", "ControlRole", "Interface"];
691
790
  for (const name of semanticProperties) {
692
791
  const value = propertyString(component, name);
693
792
  if (value === null) {
@@ -702,48 +801,48 @@ function resolveSemanticJackRole(component) {
702
801
  }
703
802
  function normalizeJackRole(value) {
704
803
  const normalized = normalizeToken(value);
705
- if (['input', 'audio-input', 'in'].includes(normalized))
706
- return 'input';
707
- if (['direct-output', 'direct-out', 'dry-output', 'dry-out'].includes(normalized))
708
- return 'direct-output';
709
- if (['output', 'audio-output', 'out'].includes(normalized))
710
- return 'output';
711
- if (normalized === 'send')
712
- return 'send';
713
- if (normalized === 'return')
714
- return 'return';
715
- if (['expression', 'exp', 'expression-pedal'].includes(normalized))
716
- return 'expression';
717
- if (['tempo-tap', 'tap-tempo', 'tempo-in', 'tap', 'tempo'].includes(normalized))
718
- return 'tempo-tap';
804
+ if (["input", "audio-input", "in"].includes(normalized))
805
+ return "input";
806
+ if (["direct-output", "direct-out", "dry-output", "dry-out"].includes(normalized))
807
+ return "direct-output";
808
+ if (["output", "audio-output", "out"].includes(normalized))
809
+ return "output";
810
+ if (normalized === "send")
811
+ return "send";
812
+ if (normalized === "return")
813
+ return "return";
814
+ if (["expression", "exp", "expression-pedal"].includes(normalized))
815
+ return "expression";
816
+ if (["tempo-tap", "tap-tempo", "tempo-in", "tap", "tempo"].includes(normalized))
817
+ return "tempo-tap";
719
818
  if ([
720
- 'external-control',
721
- 'external-control-input',
722
- 'control-input',
723
- 'remote',
724
- 'footswitch',
725
- 'trigger',
726
- 'reset',
819
+ "external-control",
820
+ "external-control-input",
821
+ "control-input",
822
+ "remote",
823
+ "footswitch",
824
+ "trigger",
825
+ "reset",
727
826
  ].includes(normalized)) {
728
- return 'external-control';
827
+ return "external-control";
729
828
  }
730
829
  return null;
731
830
  }
732
831
  function inferLedColor(component) {
733
832
  // Common pedal LED colors are usually red / amber / green. Try the part number.
734
- const part = propertyString(component, 'PartNumber')?.toLowerCase() ?? '';
735
- if (part.includes('red'))
736
- return 'red';
737
- if (part.includes('green'))
738
- return 'green';
739
- if (part.includes('amber'))
740
- return 'amber';
741
- if (part.includes('blue'))
742
- return 'blue';
743
- if (part.includes('yellow'))
744
- return 'yellow';
745
- if (part.includes('white'))
746
- return 'white';
833
+ const part = propertyString(component, "PartNumber")?.toLowerCase() ?? "";
834
+ if (part.includes("red"))
835
+ return "red";
836
+ if (part.includes("green"))
837
+ return "green";
838
+ if (part.includes("amber"))
839
+ return "amber";
840
+ if (part.includes("blue"))
841
+ return "blue";
842
+ if (part.includes("yellow"))
843
+ return "yellow";
844
+ if (part.includes("white"))
845
+ return "white";
747
846
  return undefined;
748
847
  }
749
848
  function shortType(sourceTypeName) {
@@ -824,10 +923,13 @@ function runtimeModeDefaultPosition(steps, rawValue) {
824
923
  return snapKnobPosition({ steps }, clamp01(rawValue));
825
924
  }
826
925
  function isRuntimeDescriptor(component) {
827
- return component.kind === 'ic' && component.properties.RuntimeDescriptor === 'true';
926
+ return (component.kind === "ic" && component.properties.RuntimeDescriptor === "true");
828
927
  }
829
928
  function normalizeToken(value) {
830
- return value.trim().toLowerCase().replace(/[\s_]+/g, '-');
929
+ return value
930
+ .trim()
931
+ .toLowerCase()
932
+ .replace(/[\s_]+/g, "-");
831
933
  }
832
934
  function clamp01(v) {
833
935
  if (v < 0)