@bramas/simulant-ui 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -45,6 +45,23 @@ Projects can supply a custom drawing function, agent names and aliases for
45
45
  older parameter names. Settings outside declared domains produce advisory
46
46
  warnings; execution remains available.
47
47
 
48
+ Parameter declarations describe model domains, using `in [...]` for exact finite
49
+ sets and `where` for properties. Starting values come from a bounded search,
50
+ with editable typed fallbacks when no match is found. Override them separately
51
+ in the project registry:
52
+
53
+ ```ts
54
+ simProject(model, 'cautiousPair', {
55
+ defaults: { N: 8, site: 3 },
56
+ checkSettings: () => [{ N: 5, site: 1 }, { N: 8, site: 3 }],
57
+ });
58
+ ```
59
+
60
+ `checkSettings` supplies finite settings for `check-all` when model domains
61
+ cannot be enumerated. Each setting must include every parameter; settings
62
+ outside the model domains are skipped. Without it, `check-all` enumerates the
63
+ model's finite domains. Defaults never restrict the model or select check settings.
64
+
48
65
  Renderers receive the page's colors in `options.theme` (light or dark): draw
49
66
  labels and marks with `theme.foreground` and `theme.muted` so that drawings stay
50
67
  readable in both themes. `simulator.css` is the whole stylesheet; the interface
@@ -335,7 +335,6 @@ export const SimulatorApp = (props) => {
335
335
  return { baseModel, execution: current.execute(baseModel) };
336
336
  }
337
337
  catch (e) {
338
- console.error('Project setup failed:', e);
339
338
  setSetupLog(e instanceof Error ? e.message : String(e));
340
339
  return { baseModel: null, execution: null };
341
340
  }
@@ -111,10 +111,10 @@ const HOOKS = ['beforeLook', 'beforeMove', 'afterMove'];
111
111
  /** Above this many definitions, the algorithm's facts give their number rather than their names. */
112
112
  const MANY_DEFS = 6;
113
113
  /** Counts the settings of `check-all`, up to `cap`. */
114
- function countSettings(exp, cap = 10_000) {
114
+ function countSettings(settings, cap = 10_000) {
115
115
  let n = 0;
116
116
  try {
117
- for (const _ of parameterValues(exp))
117
+ for (const _ of settings())
118
118
  if (++n >= cap)
119
119
  return `more than ${cap}`;
120
120
  }
@@ -130,7 +130,7 @@ function lineTable(exp) {
130
130
  return {};
131
131
  return Object.fromEntries(Object.entries(l.cases).flatMap(([pc, e]) => e.e === 'lit' && typeof e.value === 'number' ? [[pc, e.value]] : []));
132
132
  }
133
- export function describeExperiment(exp, sources, revision, lean) {
133
+ export function describeExperiment(exp, sources, revision, lean, checkSettings) {
134
134
  const { model, algorithm, task } = exp;
135
135
  const key = (kind, name) => `${kind} ${name}`;
136
136
  // The declarations as written. Without recorded uses (IR built otherwise), the algorithm alone.
@@ -232,9 +232,9 @@ export function describeExperiment(exp, sources, revision, lean) {
232
232
  const i = expItem(new RegExp(`^\\s+param\\s+${p.name}\\b`));
233
233
  return {
234
234
  label: `param ${p.name}`,
235
- value: p.domain ? i?.text ?? 'a domain' : 'no domain (set it in the settings)',
236
- code: !!p.domain,
237
- note: `of type ${showType(p.type)}`,
235
+ value: p.domain || p.accepts ? i?.text ?? 'a domain' : `all values of ${showType(p.type)}`,
236
+ code: !!p.domain || !!p.accepts,
237
+ note: `of type ${showType(p.type)}${p.accepts ? '; where restricts the domain' : ''}`,
238
238
  refs: expRef(i),
239
239
  };
240
240
  });
@@ -248,7 +248,7 @@ export function describeExperiment(exp, sources, revision, lean) {
248
248
  { label: 'Agents', value: agents?.text ?? 'see the experiment', code: true, refs: expRef(agents) },
249
249
  { label: 'Positions', value: position?.text ?? 'see the experiment', code: true, note: 'Initial position of agent i.', refs: expRef(position) },
250
250
  ...params,
251
- { label: 'Settings checked', value: countSettings(exp), note: 'Parameter values enumerated by check-all, from the domains above.' },
251
+ { label: 'Settings checked', value: countSettings(checkSettings ?? (() => parameterValues(exp))), note: checkSettings ? 'Finite settings supplied by project.ts, filtered through the model domains.' : 'Parameter values enumerated by check-all, from the domains above.' },
252
252
  {
253
253
  label: 'Limits',
254
254
  value: exp.limits ? Object.entries(exp.limits).map(([k, v]) => `${k} ${v}`).join(', ') : 'none',
@@ -379,7 +379,9 @@ export function describeExperiment(exp, sources, revision, lean) {
379
379
  library: lean.library.map(l => ({ module: l.module, text: l.text, refs: refTo('component', l.component) })),
380
380
  };
381
381
  const caveats = [
382
- 'Checks are bounded: they cover the settings enumerated from the parameter domains, not every ring size.',
382
+ checkSettings
383
+ ? 'Checks are bounded: they cover the finite settings supplied by project.ts, not every admissible parameter value.'
384
+ : 'Checks are bounded: they cover the settings enumerated from the parameter domains, not every ring size.',
383
385
  ...(exp.limits ? ['Exploration limits can leave a check incomplete.'] : []),
384
386
  ...(algorithm.native ? [`The algorithm's step is native TypeScript (${algorithm.native}): it is not written in .sim and is not translated to Lean.`] : []),
385
387
  ...(group.rotations ? ['Symmetry reduction relies on equivariance declarations, which are claims tested on bounded instances.'] : []),
@@ -1,4 +1,4 @@
1
- import { parameterDomainViolations, parameterValues, System } from "@bramas/simulant-engine/system";
1
+ import { parameterDefaults, parameterDomainViolations, parameterValues, System } from "@bramas/simulant-engine/system";
2
2
  import { checkFirstBranch, checkSetting, checkSettings, stateGraph } from "@bramas/simulant-engine/check";
3
3
  import { formatDiagnostic } from "@bramas/simulant-vite-plugin/module";
4
4
  import { isRenderer } from "../renderers/define.js";
@@ -57,24 +57,15 @@ function fits(value, t) {
57
57
  default: return true;
58
58
  }
59
59
  }
60
- /** The first parameter values of an experiment's domains (the form's defaults). */
61
- function firstValues(exp) {
62
- try {
63
- return parameterValues(exp).next().value;
64
- }
65
- catch {
66
- return undefined;
67
- }
68
- }
69
60
  /**
70
61
  * Settings for a new definition of the experiment (plan, Section 6.7): values
71
62
  * of parameters that still exist with a compatible type are kept; the others
72
63
  * are reset to their defaults, and each reset is noted.
73
64
  */
74
- export function adjustSettings(exp, settings) {
65
+ export function adjustSettings(exp, settings, defaults = {}) {
75
66
  if (!settings)
76
67
  return { settings, notes: [] };
77
- const first = firstValues(exp) ?? {};
68
+ const first = parameterDefaults(exp, defaults);
78
69
  const notes = [];
79
70
  const out = {};
80
71
  for (const p of exp.params) {
@@ -129,6 +120,25 @@ export function algorithmSource(exp, sources) {
129
120
  }
130
121
  export function simProject(module, experiment, opts = {}) {
131
122
  const draw = opts.draw ?? drawRing;
123
+ const defaultsOf = (exp) => Object.fromEntries(exp.params
124
+ .filter(p => opts.defaults && p.name in opts.defaults)
125
+ .map(p => [p.name, coerce(opts.defaults[p.name], p.type)]));
126
+ const coerceSettings = (exp, settings) => Object.fromEntries(exp.params
127
+ .filter(p => p.name in settings).map(p => [p.name, coerce(settings[p.name], p.type)]));
128
+ function* settingsFor(exp) {
129
+ if (!opts.checkSettings) {
130
+ yield* parameterValues(exp);
131
+ return;
132
+ }
133
+ for (const given of opts.checkSettings(exp)) {
134
+ const params = coerceSettings(exp, renameSettings(given, opts.aliases));
135
+ for (const p of exp.params)
136
+ if (!(p.name in params))
137
+ throw new Error(`checkSettings is missing parameter ${p.name}`);
138
+ if (!parameterDomainViolations(exp, params).length)
139
+ yield params;
140
+ }
141
+ }
132
142
  const lazy = (f) => {
133
143
  let done = false, value;
134
144
  return () => { if (!done) {
@@ -140,7 +150,7 @@ export function simProject(module, experiment, opts = {}) {
140
150
  const exp = m.experiments[experiment];
141
151
  if (!exp)
142
152
  return undefined;
143
- const first = lazy(() => firstValues(exp));
153
+ const first = lazy(() => parameterDefaults(exp, defaultsOf(exp)));
144
154
  // Line information only affects the algorithm and model views: an edit that only moves lines redraws.
145
155
  const { line: _line, source: _source, ...algorithm } = exp.algorithm;
146
156
  const { source: _expSource, ...rest } = exp;
@@ -148,7 +158,7 @@ export function simProject(module, experiment, opts = {}) {
148
158
  // Lines of expressions (`at`) are display only, like the line table.
149
159
  exp, key: JSON.stringify({ ...rest, algorithm }, (k, v) => k === 'at' ? undefined : v), first,
150
160
  source: algorithmSource(exp, m.sources ?? {}),
151
- description: lazy(() => describeExperiment(exp, m.sources ?? {}, m.revision, m.lean?.[experiment])),
161
+ description: lazy(() => describeExperiment(exp, m.sources ?? {}, m.revision, m.lean?.[experiment], opts.checkSettings && (() => settingsFor(exp)))),
152
162
  editorSchema: lazy(() => ({ fields: exp.params.map(p => field(p.name, p.type, first()?.[p.name])) })),
153
163
  };
154
164
  };
@@ -178,7 +188,7 @@ export function simProject(module, experiment, opts = {}) {
178
188
  return;
179
189
  }
180
190
  else
181
- emit({ kind: 'replaced', revision, adjust: settings => adjustSettings(loaded.exp, renameSettings(settings, opts.aliases)) });
191
+ emit({ kind: 'replaced', revision, adjust: settings => adjustSettings(loaded.exp, renameSettings(settings, opts.aliases), defaultsOf(loaded.exp)) });
182
192
  });
183
193
  if (isRenderer(draw))
184
194
  draw.subscribe(() => emit({ kind: 'redraw' }));
@@ -257,7 +267,7 @@ export function simProject(module, experiment, opts = {}) {
257
267
  checkAll: async (o = {}, onProgress) => {
258
268
  const rev = revision;
259
269
  const { exp } = need();
260
- return report(await checkSettings(exp, parameterValues(exp), {
270
+ return report(await checkSettings(exp, settingsFor(exp), {
261
271
  ...limits(o), shared: !o.perSetting, maxConfigs: o.maxConfigs,
262
272
  }, o.signal && { signal: o.signal }, onProgress), rev);
263
273
  },
@@ -300,7 +310,7 @@ export function simProject(module, experiment, opts = {}) {
300
310
  },
301
311
  settingsGenerator: function* () {
302
312
  if (current)
303
- yield* parameterValues(current.exp);
313
+ yield* settingsFor(current.exp);
304
314
  },
305
315
  get editorSchema() {
306
316
  return current?.editorSchema() ?? { fields: [] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bramas/simulant-ui",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "license": "CECILL-B",
6
6
  "type": "module",
@@ -31,11 +31,11 @@
31
31
  }
32
32
  },
33
33
  "dependencies": {
34
- "@bramas/simulant-core": "0.2.0",
35
- "@bramas/simulant-lang": "0.2.0",
36
- "@bramas/simulant-lean-gen": "0.2.0",
37
- "@bramas/simulant-engine": "0.2.0",
38
- "@bramas/simulant-vite-plugin": "0.2.0"
34
+ "@bramas/simulant-lang": "0.3.0",
35
+ "@bramas/simulant-core": "0.3.0",
36
+ "@bramas/simulant-engine": "0.3.0",
37
+ "@bramas/simulant-lean-gen": "0.3.0",
38
+ "@bramas/simulant-vite-plugin": "0.3.0"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "solid-js": "^1.9.3"
@@ -371,7 +371,6 @@ export const SimulatorApp: Component<SimulatorAppProps> = (props) => {
371
371
  setSetupLog('');
372
372
  return { baseModel, execution: current.execute(baseModel) };
373
373
  } catch (e) {
374
- console.error('Project setup failed:', e);
375
374
  setSetupLog(e instanceof Error ? e.message : String(e));
376
375
  return { baseModel: null, execution: null };
377
376
  }
@@ -115,10 +115,10 @@ const HOOKS = ['beforeLook', 'beforeMove', 'afterMove'] as const;
115
115
  const MANY_DEFS = 6;
116
116
 
117
117
  /** Counts the settings of `check-all`, up to `cap`. */
118
- function countSettings(exp: Experiment, cap = 10_000): string {
118
+ function countSettings(settings: () => Iterable<unknown>, cap = 10_000): string {
119
119
  let n = 0;
120
120
  try {
121
- for (const _ of parameterValues(exp)) if (++n >= cap) return `more than ${cap}`;
121
+ for (const _ of settings()) if (++n >= cap) return `more than ${cap}`;
122
122
  } catch {
123
123
  return 'unknown (a domain cannot be enumerated)';
124
124
  }
@@ -132,7 +132,7 @@ function lineTable(exp: Experiment): Record<string, number> {
132
132
  return Object.fromEntries(Object.entries(l.cases).flatMap(([pc, e]) => e.e === 'lit' && typeof e.value === 'number' ? [[pc, e.value]] : []));
133
133
  }
134
134
 
135
- export function describeExperiment(exp: Experiment, sources: Record<string, string>, revision?: string, lean?: SimLean): ModelDescription {
135
+ export function describeExperiment(exp: Experiment, sources: Record<string, string>, revision?: string, lean?: SimLean, checkSettings?: () => Iterable<unknown>): ModelDescription {
136
136
  const { model, algorithm, task } = exp;
137
137
  const key = (kind: string, name: string) => `${kind} ${name}`;
138
138
 
@@ -235,9 +235,9 @@ export function describeExperiment(exp: Experiment, sources: Record<string, stri
235
235
  const i = expItem(new RegExp(`^\\s+param\\s+${p.name}\\b`));
236
236
  return {
237
237
  label: `param ${p.name}`,
238
- value: p.domain ? i?.text ?? 'a domain' : 'no domain (set it in the settings)',
239
- code: !!p.domain,
240
- note: `of type ${showType(p.type)}`,
238
+ value: p.domain || p.accepts ? i?.text ?? 'a domain' : `all values of ${showType(p.type)}`,
239
+ code: !!p.domain || !!p.accepts,
240
+ note: `of type ${showType(p.type)}${p.accepts ? '; where restricts the domain' : ''}`,
241
241
  refs: expRef(i),
242
242
  };
243
243
  });
@@ -252,7 +252,7 @@ export function describeExperiment(exp: Experiment, sources: Record<string, stri
252
252
  { label: 'Agents', value: agents?.text ?? 'see the experiment', code: true, refs: expRef(agents) },
253
253
  { label: 'Positions', value: position?.text ?? 'see the experiment', code: true, note: 'Initial position of agent i.', refs: expRef(position) },
254
254
  ...params,
255
- { label: 'Settings checked', value: countSettings(exp), note: 'Parameter values enumerated by check-all, from the domains above.' },
255
+ { label: 'Settings checked', value: countSettings(checkSettings ?? (() => parameterValues(exp))), note: checkSettings ? 'Finite settings supplied by project.ts, filtered through the model domains.' : 'Parameter values enumerated by check-all, from the domains above.' },
256
256
  {
257
257
  label: 'Limits',
258
258
  value: exp.limits ? Object.entries(exp.limits).map(([k, v]) => `${k} ${v}`).join(', ') : 'none',
@@ -386,7 +386,9 @@ export function describeExperiment(exp: Experiment, sources: Record<string, stri
386
386
  };
387
387
 
388
388
  const caveats = [
389
- 'Checks are bounded: they cover the settings enumerated from the parameter domains, not every ring size.',
389
+ checkSettings
390
+ ? 'Checks are bounded: they cover the finite settings supplied by project.ts, not every admissible parameter value.'
391
+ : 'Checks are bounded: they cover the settings enumerated from the parameter domains, not every ring size.',
390
392
  ...(exp.limits ? ['Exploration limits can leave a check incomplete.'] : []),
391
393
  ...(algorithm.native ? [`The algorithm's step is native TypeScript (${algorithm.native}): it is not written in .sim and is not translated to Lean.`] : []),
392
394
  ...(group.rotations ? ['Symmetry reduction relies on equivariance declarations, which are claims tested on bounded instances.'] : []),
@@ -6,7 +6,7 @@
6
6
  * `draw`, the algorithm view from the algorithm's source and line table.
7
7
  */
8
8
  import type { Experiment, Type } from '@bramas/simulant-lang/ir';
9
- import { parameterDomainViolations, parameterValues, System } from '@bramas/simulant-engine/system';
9
+ import { parameterDefaults, parameterDomainViolations, parameterValues, System } from '@bramas/simulant-engine/system';
10
10
  import { checkFirstBranch, checkSetting, checkSettings, stateGraph, type CheckResult } from '@bramas/simulant-engine/check';
11
11
  import type { EditorField, EditorSchema } from '@bramas/simulant-core/types/editor-schema';
12
12
  import type { AlgorithmSource, CheckOptions, ModelDescription, ProjectType, ProjectUpdate } from '@bramas/simulant-core/types/project';
@@ -41,6 +41,10 @@ export type SimProjectOptions = {
41
41
  * `{ BH_node: 'site' }` reads `BH_node` as `site` when `site` is not given.
42
42
  */
43
43
  aliases?: Record<string, string>;
44
+ /** Simulator starting values, independent of the model's parameter domains. */
45
+ defaults?: Record<string, unknown>;
46
+ /** Finite settings for check-all when the model's domains cannot be enumerated. */
47
+ checkSettings?: (experiment: Experiment) => Iterable<Record<string, unknown>>;
44
48
  };
45
49
 
46
50
  /** Settings with older parameter names renamed (see `SimProjectOptions.aliases`). */
@@ -86,23 +90,14 @@ function fits(value: unknown, t: Type): boolean {
86
90
  }
87
91
  }
88
92
 
89
- /** The first parameter values of an experiment's domains (the form's defaults). */
90
- function firstValues(exp: Experiment): Record<string, unknown> | undefined {
91
- try {
92
- return parameterValues(exp).next().value as Record<string, unknown> | undefined;
93
- } catch {
94
- return undefined;
95
- }
96
- }
97
-
98
93
  /**
99
94
  * Settings for a new definition of the experiment (plan, Section 6.7): values
100
95
  * of parameters that still exist with a compatible type are kept; the others
101
96
  * are reset to their defaults, and each reset is noted.
102
97
  */
103
- export function adjustSettings(exp: Experiment, settings: Record<string, unknown> | null): { settings: Record<string, unknown> | null; notes: string[] } {
98
+ export function adjustSettings(exp: Experiment, settings: Record<string, unknown> | null, defaults: Record<string, unknown> = {}): { settings: Record<string, unknown> | null; notes: string[] } {
104
99
  if (!settings) return { settings, notes: [] };
105
- const first = firstValues(exp) ?? {};
100
+ const first = parameterDefaults(exp, defaults);
106
101
  const notes: string[] = [];
107
102
  const out: Record<string, unknown> = {};
108
103
  for (const p of exp.params) {
@@ -153,12 +148,25 @@ export function algorithmSource(exp: Experiment, sources: Record<string, string>
153
148
 
154
149
  export function simProject(module: SimSources, experiment: string, opts: SimProjectOptions = {}): ProjectType<any, any> {
155
150
  const draw = opts.draw ?? drawRing;
151
+ const defaultsOf = (exp: Experiment) => Object.fromEntries(exp.params
152
+ .filter(p => opts.defaults && p.name in opts.defaults)
153
+ .map(p => [p.name, coerce(opts.defaults![p.name], p.type)]));
154
+ const coerceSettings = (exp: Experiment, settings: Record<string, unknown>) => Object.fromEntries(exp.params
155
+ .filter(p => p.name in settings).map(p => [p.name, coerce(settings[p.name], p.type)]));
156
+ function* settingsFor(exp: Experiment) {
157
+ if (!opts.checkSettings) { yield* parameterValues(exp); return; }
158
+ for (const given of opts.checkSettings(exp)) {
159
+ const params = coerceSettings(exp, renameSettings(given, opts.aliases));
160
+ for (const p of exp.params) if (!(p.name in params)) throw new Error(`checkSettings is missing parameter ${p.name}`);
161
+ if (!parameterDomainViolations(exp, params).length) yield params;
162
+ }
163
+ }
156
164
 
157
165
  // What the project runs: the last definition that compiled, replaced on hot updates.
158
166
  type Current = {
159
167
  exp: Experiment; key: string;
160
- /** The defaults, computed when first needed (a domain may take time to enumerate). */
161
- first: () => Record<string, unknown> | undefined; editorSchema: () => EditorSchema;
168
+ /** Defaults are computed lazily; explicit domains may take time to evaluate. */
169
+ first: () => Record<string, unknown>; editorSchema: () => EditorSchema;
162
170
  source: AlgorithmSource;
163
171
  description: () => ModelDescription;
164
172
  };
@@ -169,7 +177,7 @@ export function simProject(module: SimSources, experiment: string, opts: SimProj
169
177
  const load = (m: SimSources): Current | undefined => {
170
178
  const exp = m.experiments[experiment];
171
179
  if (!exp) return undefined;
172
- const first = lazy(() => firstValues(exp));
180
+ const first = lazy(() => parameterDefaults(exp, defaultsOf(exp)));
173
181
  // Line information only affects the algorithm and model views: an edit that only moves lines redraws.
174
182
  const { line: _line, source: _source, ...algorithm } = exp.algorithm;
175
183
  const { source: _expSource, ...rest } = exp;
@@ -177,7 +185,7 @@ export function simProject(module: SimSources, experiment: string, opts: SimProj
177
185
  // Lines of expressions (`at`) are display only, like the line table.
178
186
  exp, key: JSON.stringify({ ...rest, algorithm }, (k, v) => k === 'at' ? undefined : v), first,
179
187
  source: algorithmSource(exp, m.sources ?? {}),
180
- description: lazy(() => describeExperiment(exp, m.sources ?? {}, m.revision, m.lean?.[experiment])),
188
+ description: lazy(() => describeExperiment(exp, m.sources ?? {}, m.revision, m.lean?.[experiment], opts.checkSettings && (() => settingsFor(exp)))),
181
189
  editorSchema: lazy(() => ({ fields: exp.params.map(p => field(p.name, p.type, first()?.[p.name])) })),
182
190
  };
183
191
  };
@@ -206,7 +214,7 @@ export function simProject(module: SimSources, experiment: string, opts: SimProj
206
214
  emit({ kind: 'redraw' });
207
215
  return;
208
216
  }
209
- else emit({ kind: 'replaced', revision, adjust: settings => adjustSettings(loaded.exp, renameSettings(settings, opts.aliases)) });
217
+ else emit({ kind: 'replaced', revision, adjust: settings => adjustSettings(loaded.exp, renameSettings(settings, opts.aliases), defaultsOf(loaded.exp)) });
210
218
  });
211
219
  if (isRenderer(draw)) draw.subscribe(() => emit({ kind: 'redraw' }));
212
220
 
@@ -287,7 +295,7 @@ export function simProject(module: SimSources, experiment: string, opts: SimProj
287
295
  checkAll: async (o = {}, onProgress) => {
288
296
  const rev = revision;
289
297
  const { exp } = need();
290
- return report(await checkSettings(exp, parameterValues(exp), {
298
+ return report(await checkSettings(exp, settingsFor(exp), {
291
299
  ...limits(o), shared: !o.perSetting, maxConfigs: o.maxConfigs,
292
300
  }, o.signal && { signal: o.signal }, onProgress), rev);
293
301
  },
@@ -328,7 +336,7 @@ export function simProject(module: SimSources, experiment: string, opts: SimProj
328
336
  return v === 'success' && model.system.exp.task.goal !== 'eventually' ? 'inProgress' : v;
329
337
  },
330
338
  settingsGenerator: function* () {
331
- if (current) yield* parameterValues(current.exp);
339
+ if (current) yield* settingsFor(current.exp);
332
340
  },
333
341
  get editorSchema() {
334
342
  return current?.editorSchema() ?? { fields: [] };