@logic-pad/core 0.19.1 → 0.21.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.
@@ -146,6 +146,27 @@ declare global {
146
146
  Solve = 'solve',
147
147
  Perfection = 'perfection',
148
148
  }
149
+ export declare enum Instrument {
150
+ Piano = 'piano',
151
+ Drum = 'drum',
152
+ Violin = 'violin',
153
+ Xylophone = 'xylophone',
154
+ GuitarAcoustic = 'guitar-acoustic',
155
+ GuitarElectric = 'guitar-electric',
156
+ Flute = 'flute',
157
+ Trumpet = 'trumpet',
158
+ }
159
+ export declare const INSTRUMENTS: readonly Instrument[];
160
+ export declare const DRUM_SAMPLES: readonly [
161
+ 'snare',
162
+ 'kick',
163
+ 'hihat',
164
+ 'hihat-open',
165
+ 'crash',
166
+ 'tom',
167
+ 'rim',
168
+ ];
169
+ export declare function isDrumSample(note: string): boolean;
149
170
  export declare class GridZones {
150
171
  readonly edges: readonly Edge[];
151
172
  constructor(edges?: readonly Edge[]);
@@ -490,6 +511,12 @@ declare global {
490
511
  * If this is null from the first control line, the note will be silent.
491
512
  */
492
513
  readonly note: string | null;
514
+ /**
515
+ * The instrument to play the note with, or null to keep the current instrument from the previous control line.
516
+ * If this is null from the first control line, the instrument will be "piano".
517
+ * This has no effect if the current note is a drum sample.
518
+ */
519
+ readonly instrument: Instrument | null;
493
520
  /**
494
521
  * The velocity to play the note at, or null to keep the current velocity from the previous control line.
495
522
  * Ranges from 0 to 1
@@ -505,6 +532,12 @@ declare global {
505
532
  * If this is null from the first control line, the note will be silent.
506
533
  */
507
534
  note: string | null,
535
+ /**
536
+ * The instrument to play the note with, or null to keep the current instrument from the previous control line.
537
+ * If this is null from the first control line, the instrument will be "piano".
538
+ * This has no effect if the current note is a drum sample.
539
+ */
540
+ instrument: Instrument | null,
508
541
  /**
509
542
  * The velocity to play the note at, or null to keep the current velocity from the previous control line.
510
543
  * Ranges from 0 to 1
@@ -514,9 +547,11 @@ declare global {
514
547
  get configs(): readonly AnyConfig[] | null;
515
548
  copyWith({
516
549
  note,
550
+ instrument,
517
551
  velocity,
518
552
  }: {
519
553
  note?: string | null;
554
+ instrument?: Instrument | null;
520
555
  velocity?: number | null;
521
556
  }): this;
522
557
  }
@@ -1219,6 +1254,7 @@ declare global {
1219
1254
  Icon = 'icon',
1220
1255
  ControlLines = 'controlLines',
1221
1256
  NullableNote = 'nullableNote',
1257
+ NullableInstrument = 'nullableInstrument',
1222
1258
  SolvePath = 'solvePath',
1223
1259
  }
1224
1260
  export interface Config<T> {
@@ -1298,6 +1334,9 @@ declare global {
1298
1334
  export interface NullableNoteConfig extends Config<string | null> {
1299
1335
  readonly type: ConfigType.NullableNote;
1300
1336
  }
1337
+ export interface NullableInstrumentConfig extends Config<Instrument | null> {
1338
+ readonly type: ConfigType.NullableInstrument;
1339
+ }
1301
1340
  export interface SolvePathConfig extends Config<Position$1[]> {
1302
1341
  readonly type: ConfigType.SolvePath;
1303
1342
  }
@@ -1321,6 +1360,7 @@ declare global {
1321
1360
  | IconConfig
1322
1361
  | ControlLinesConfig
1323
1362
  | NullableNoteConfig
1363
+ | NullableInstrumentConfig
1324
1364
  | SolvePathConfig;
1325
1365
  /**
1326
1366
  * Compare two config values for equality, using an appropriate method for the config type.
@@ -3113,6 +3153,21 @@ declare global {
3113
3153
  grid: GridData,
3114
3154
  solution: GridData | null
3115
3155
  ): GridState;
3156
+ export declare class GridValidator {
3157
+ private worker;
3158
+ private stateListeners;
3159
+ private loadListeners;
3160
+ private readonly validateGridDebounced;
3161
+ readonly validateGrid: (grid: GridData, solution: GridData | null) => void;
3162
+ private readonly notifyState;
3163
+ readonly subscribeToState: (
3164
+ listener: (state: GridState) => void
3165
+ ) => () => void;
3166
+ private readonly notifyLoad;
3167
+ readonly subscribeToLoad: (listener: () => void) => () => void;
3168
+ readonly isLoading: () => boolean;
3169
+ readonly delete: () => void;
3170
+ }
3116
3171
 
3117
3172
  export { Symbol$1 as Symbol, escape$1 as escape, unescape$1 as unescape };
3118
3173
 
@@ -1,5 +1,5 @@
1
1
  import GridData from './grid.js';
2
- import { Color, Comparison, Direction, DirectionToggle, Orientation, OrientationToggle, Position, Wrapping } from './primitives.js';
2
+ import { Color, Comparison, Direction, DirectionToggle, Instrument, Orientation, OrientationToggle, Position, Wrapping } from './primitives.js';
3
3
  import { ControlLine } from './rules/musicControlLine.js';
4
4
  export declare enum ConfigType {
5
5
  Boolean = "boolean",
@@ -21,6 +21,7 @@ export declare enum ConfigType {
21
21
  Icon = "icon",
22
22
  ControlLines = "controlLines",
23
23
  NullableNote = "nullableNote",
24
+ NullableInstrument = "nullableInstrument",
24
25
  SolvePath = "solvePath"
25
26
  }
26
27
  export interface Config<T> {
@@ -100,10 +101,13 @@ export interface ControlLinesConfig extends Config<ControlLine[]> {
100
101
  export interface NullableNoteConfig extends Config<string | null> {
101
102
  readonly type: ConfigType.NullableNote;
102
103
  }
104
+ export interface NullableInstrumentConfig extends Config<Instrument | null> {
105
+ readonly type: ConfigType.NullableInstrument;
106
+ }
103
107
  export interface SolvePathConfig extends Config<Position[]> {
104
108
  readonly type: ConfigType.SolvePath;
105
109
  }
106
- export type AnyConfig = BooleanConfig | NullableBooleanConfig | NumberConfig | NullableNumberConfig | StringConfig | ColorConfig | ComparisonConfig | WrappingConfig | DirectionConfig | DirectionToggleConfig | OrientationConfig | OrientationToggleConfig | TileConfig | ShapeConfig | GridConfig | NullableGridConfig | IconConfig | ControlLinesConfig | NullableNoteConfig | SolvePathConfig;
110
+ export type AnyConfig = BooleanConfig | NullableBooleanConfig | NumberConfig | NullableNumberConfig | StringConfig | ColorConfig | ComparisonConfig | WrappingConfig | DirectionConfig | DirectionToggleConfig | OrientationConfig | OrientationToggleConfig | TileConfig | ShapeConfig | GridConfig | NullableGridConfig | IconConfig | ControlLinesConfig | NullableNoteConfig | NullableInstrumentConfig | SolvePathConfig;
107
111
  /**
108
112
  * Compare two config values for equality, using an appropriate method for the config type.
109
113
  *
@@ -21,6 +21,7 @@ export var ConfigType;
21
21
  ConfigType["Icon"] = "icon";
22
22
  ConfigType["ControlLines"] = "controlLines";
23
23
  ConfigType["NullableNote"] = "nullableNote";
24
+ ConfigType["NullableInstrument"] = "nullableInstrument";
24
25
  ConfigType["SolvePath"] = "solvePath";
25
26
  })(ConfigType || (ConfigType = {}));
26
27
  /**
@@ -123,3 +123,16 @@ export declare enum Mode {
123
123
  Solve = "solve",
124
124
  Perfection = "perfection"
125
125
  }
126
+ export declare enum Instrument {
127
+ Piano = "piano",
128
+ Drum = "drum",
129
+ Violin = "violin",
130
+ Xylophone = "xylophone",
131
+ GuitarAcoustic = "guitar-acoustic",
132
+ GuitarElectric = "guitar-electric",
133
+ Flute = "flute",
134
+ Trumpet = "trumpet"
135
+ }
136
+ export declare const INSTRUMENTS: readonly Instrument[];
137
+ export declare const DRUM_SAMPLES: readonly ["snare", "kick", "hihat", "hihat-open", "crash", "tom", "rim"];
138
+ export declare function isDrumSample(note: string): boolean;
@@ -142,3 +142,36 @@ export var Mode;
142
142
  Mode["Solve"] = "solve";
143
143
  Mode["Perfection"] = "perfection";
144
144
  })(Mode || (Mode = {}));
145
+ export var Instrument;
146
+ (function (Instrument) {
147
+ Instrument["Piano"] = "piano";
148
+ Instrument["Drum"] = "drum";
149
+ Instrument["Violin"] = "violin";
150
+ Instrument["Xylophone"] = "xylophone";
151
+ Instrument["GuitarAcoustic"] = "guitar-acoustic";
152
+ Instrument["GuitarElectric"] = "guitar-electric";
153
+ Instrument["Flute"] = "flute";
154
+ Instrument["Trumpet"] = "trumpet";
155
+ })(Instrument || (Instrument = {}));
156
+ export const INSTRUMENTS = [
157
+ Instrument.Piano,
158
+ Instrument.Drum,
159
+ Instrument.Violin,
160
+ Instrument.Xylophone,
161
+ Instrument.GuitarAcoustic,
162
+ Instrument.GuitarElectric,
163
+ Instrument.Flute,
164
+ Instrument.Trumpet,
165
+ ];
166
+ export const DRUM_SAMPLES = [
167
+ 'snare',
168
+ 'kick',
169
+ 'hihat',
170
+ 'hihat-open',
171
+ 'crash',
172
+ 'tom',
173
+ 'rim',
174
+ ];
175
+ export function isDrumSample(note) {
176
+ return DRUM_SAMPLES.includes(note);
177
+ }
@@ -1,11 +1,18 @@
1
1
  import { AnyConfig } from '../config.js';
2
2
  import Configurable from '../configurable.js';
3
+ import { Instrument } from '../primitives.js';
3
4
  export declare class Row extends Configurable {
4
5
  /**
5
6
  * The note to play at this row, or null to keep the current note from the previous control line.
6
7
  * If this is null from the first control line, the note will be silent.
7
8
  */
8
9
  readonly note: string | null;
10
+ /**
11
+ * The instrument to play the note with, or null to keep the current instrument from the previous control line.
12
+ * If this is null from the first control line, the instrument will be "piano".
13
+ * This has no effect if the current note is a drum sample.
14
+ */
15
+ readonly instrument: Instrument | null;
9
16
  /**
10
17
  * The velocity to play the note at, or null to keep the current velocity from the previous control line.
11
18
  * Ranges from 0 to 1
@@ -20,14 +27,21 @@ export declare class Row extends Configurable {
20
27
  * If this is null from the first control line, the note will be silent.
21
28
  */
22
29
  note: string | null,
30
+ /**
31
+ * The instrument to play the note with, or null to keep the current instrument from the previous control line.
32
+ * If this is null from the first control line, the instrument will be "piano".
33
+ * This has no effect if the current note is a drum sample.
34
+ */
35
+ instrument: Instrument | null,
23
36
  /**
24
37
  * The velocity to play the note at, or null to keep the current velocity from the previous control line.
25
38
  * Ranges from 0 to 1
26
39
  */
27
40
  velocity: number | null);
28
41
  get configs(): readonly AnyConfig[] | null;
29
- copyWith({ note, velocity, }: {
42
+ copyWith({ note, instrument, velocity, }: {
30
43
  note?: string | null;
44
+ instrument?: Instrument | null;
31
45
  velocity?: number | null;
32
46
  }): this;
33
47
  }
@@ -1,5 +1,6 @@
1
1
  import { ConfigType } from '../config.js';
2
2
  import Configurable from '../configurable.js';
3
+ import { Instrument } from '../primitives.js';
3
4
  export class Row extends Configurable {
4
5
  constructor(
5
6
  /**
@@ -7,6 +8,12 @@ export class Row extends Configurable {
7
8
  * If this is null from the first control line, the note will be silent.
8
9
  */
9
10
  note,
11
+ /**
12
+ * The instrument to play the note with, or null to keep the current instrument from the previous control line.
13
+ * If this is null from the first control line, the instrument will be "piano".
14
+ * This has no effect if the current note is a drum sample.
15
+ */
16
+ instrument,
10
17
  /**
11
18
  * The velocity to play the note at, or null to keep the current velocity from the previous control line.
12
19
  * Ranges from 0 to 1
@@ -19,6 +26,12 @@ export class Row extends Configurable {
19
26
  writable: true,
20
27
  value: note
21
28
  });
29
+ Object.defineProperty(this, "instrument", {
30
+ enumerable: true,
31
+ configurable: true,
32
+ writable: true,
33
+ value: instrument
34
+ });
22
35
  Object.defineProperty(this, "velocity", {
23
36
  enumerable: true,
24
37
  configurable: true,
@@ -38,13 +51,14 @@ export class Row extends Configurable {
38
51
  value: 'Configure the playback settings from this tile onwards.'
39
52
  });
40
53
  this.note = note;
54
+ this.instrument = instrument;
41
55
  this.velocity = velocity;
42
56
  }
43
57
  get configs() {
44
58
  return Row.CONFIGS;
45
59
  }
46
- copyWith({ note, velocity, }) {
47
- return new Row(note !== undefined ? note : this.note, velocity !== undefined ? velocity : this.velocity);
60
+ copyWith({ note, instrument, velocity, }) {
61
+ return new Row(note !== undefined ? note : this.note, instrument !== undefined ? instrument : this.instrument, velocity !== undefined ? velocity : this.velocity);
48
62
  }
49
63
  }
50
64
  Object.defineProperty(Row, "CONFIGS", {
@@ -60,6 +74,14 @@ Object.defineProperty(Row, "CONFIGS", {
60
74
  explanation: 'The musical note or sample to play.',
61
75
  configurable: true,
62
76
  },
77
+ {
78
+ type: ConfigType.NullableInstrument,
79
+ default: Instrument.Piano,
80
+ field: 'instrument',
81
+ description: 'Instrument',
82
+ explanation: 'The musical instrument to use. This has no effect if the current note is a drum sample.',
83
+ configurable: true,
84
+ },
63
85
  {
64
86
  type: ConfigType.NullableNumber,
65
87
  default: 0.5,
@@ -68,7 +90,7 @@ Object.defineProperty(Row, "CONFIGS", {
68
90
  step: 0.2,
69
91
  field: 'velocity',
70
92
  description: 'Velocity',
71
- explanation: 'For piano notes, how hard the note is played.',
93
+ explanation: 'The volume to play the note at.',
72
94
  configurable: true,
73
95
  },
74
96
  ])
@@ -1,19 +1,19 @@
1
1
  import { ConfigType } from '../config.js';
2
2
  import GridData from '../grid.js';
3
3
  import { resize } from '../dataHelper.js';
4
- import { Color, MajorRule, State } from '../primitives.js';
4
+ import { Color, Instrument, MajorRule, State, } from '../primitives.js';
5
5
  import CustomIconSymbol from '../symbols/customIconSymbol.js';
6
6
  import { ControlLine, Row } from './musicControlLine.js';
7
7
  import Rule from './rule.js';
8
- const DEFAULT_SCALLE = [
9
- new Row('C5', null),
10
- new Row('B4', null),
11
- new Row('A4', null),
12
- new Row('G4', null),
13
- new Row('F4', null),
14
- new Row('E4', null),
15
- new Row('D4', null),
16
- new Row('C4', null),
8
+ const DEFAULT_SCALE = [
9
+ new Row('C5', Instrument.Piano, null),
10
+ new Row('B4', Instrument.Piano, null),
11
+ new Row('A4', Instrument.Piano, null),
12
+ new Row('G4', Instrument.Piano, null),
13
+ new Row('F4', Instrument.Piano, null),
14
+ new Row('E4', Instrument.Piano, null),
15
+ new Row('D4', Instrument.Piano, null),
16
+ new Row('C4', Instrument.Piano, null),
17
17
  ];
18
18
  class MusicGridRule extends Rule {
19
19
  get configExplanation() {
@@ -87,7 +87,7 @@ class MusicGridRule extends Rule {
87
87
  return this;
88
88
  const controlLines = this.controlLines
89
89
  .filter(line => line.column < newGrid.width)
90
- .map(line => line.withRows(resize(line.rows, newGrid.height, () => new Row(null, null))));
90
+ .map(line => line.withRows(resize(line.rows, newGrid.height, () => new Row(null, null, null))));
91
91
  return this.copyWith({ controlLines });
92
92
  }
93
93
  onGridResize(_grid, mode, direction, index) {
@@ -96,7 +96,7 @@ class MusicGridRule extends Rule {
96
96
  return this.copyWith({
97
97
  controlLines: this.controlLines.map(line => {
98
98
  const rows = line.rows.slice();
99
- rows.splice(index, 0, new Row(null, null));
99
+ rows.splice(index, 0, new Row(null, null, null));
100
100
  return line.withRows(rows);
101
101
  }),
102
102
  });
@@ -165,10 +165,13 @@ class MusicGridRule extends Rule {
165
165
  const note = lines
166
166
  .map(l => l.rows[idx]?.note)
167
167
  .reduce((a, b) => b ?? a, null);
168
+ const instrument = lines
169
+ .map(l => l.rows[idx]?.instrument)
170
+ .reduce((a, b) => b ?? a, null);
168
171
  const velocity = lines
169
172
  .map(l => l.rows[idx]?.velocity)
170
173
  .reduce((a, b) => b ?? a, null);
171
- return new Row(note, velocity);
174
+ return new Row(note, instrument, velocity);
172
175
  });
173
176
  const bpm = lines.map(l => l.bpm).reduce((a, b) => b ?? a, null);
174
177
  const pedal = lines.map(l => l.pedal).reduce((a, b) => b ?? a, null);
@@ -201,7 +204,7 @@ Object.defineProperty(MusicGridRule, "CONFIGS", {
201
204
  value: Object.freeze([
202
205
  {
203
206
  type: ConfigType.ControlLines,
204
- default: [new ControlLine(0, 120, false, false, DEFAULT_SCALLE)],
207
+ default: [new ControlLine(0, 120, false, false, DEFAULT_SCALE)],
205
208
  field: 'controlLines',
206
209
  description: 'Control Lines',
207
210
  configurable: false,
@@ -214,7 +217,7 @@ Object.defineProperty(MusicGridRule, "CONFIGS", {
214
217
  'wwwww',
215
218
  'wwwww',
216
219
  'wwwww',
217
- ]).addRule(new MusicGridRule([new ControlLine(0, 120, false, false, DEFAULT_SCALLE)], null)),
220
+ ]).addRule(new MusicGridRule([new ControlLine(0, 120, false, false, DEFAULT_SCALE)], null)),
218
221
  field: 'track',
219
222
  description: 'Track',
220
223
  explanation: 'If set, this grid will be played instead of the solution.',
@@ -235,8 +238,8 @@ Object.defineProperty(MusicGridRule, "SEARCH_VARIANTS", {
235
238
  configurable: true,
236
239
  writable: true,
237
240
  value: [
238
- new MusicGridRule([new ControlLine(0, 120, false, false, DEFAULT_SCALLE)], null).searchVariant(),
241
+ new MusicGridRule([new ControlLine(0, 120, false, false, DEFAULT_SCALE)], null).searchVariant(),
239
242
  ]
240
243
  });
241
244
  export default MusicGridRule;
242
- export const instance = new MusicGridRule([new ControlLine(0, 120, false, false, DEFAULT_SCALLE)], null);
245
+ export const instance = new MusicGridRule([new ControlLine(0, 120, false, false, DEFAULT_SCALE)], null);
@@ -6,8 +6,9 @@ function ensureCompressionStream() {
6
6
  }
7
7
  return Promise.resolve();
8
8
  }
9
+ const encoder = new TextEncoder();
10
+ const decoder = new TextDecoder();
9
11
  export default class StreamCompressor extends CompressorBase {
10
- /* eslint-disable @typescript-eslint/no-floating-promises */
11
12
  async compress(input) {
12
13
  await ensureCompressionStream();
13
14
  const blobToBase64 = (blob) => new Promise(resolve => {
@@ -15,22 +16,27 @@ export default class StreamCompressor extends CompressorBase {
15
16
  reader.onloadend = () => resolve(reader.result.split(',')[1]);
16
17
  reader.readAsDataURL(blob);
17
18
  });
18
- const byteArray = new TextEncoder().encode(input);
19
+ const byteArray = encoder.encode(input);
19
20
  const cs = new CompressionStream(this.algorithm);
20
21
  const writer = cs.writable.getWriter();
21
- writer.write(byteArray);
22
- writer.close();
22
+ writer.ready
23
+ .then(() => writer.write(byteArray))
24
+ .then(() => writer.close())
25
+ .catch(console.log);
23
26
  return new Response(cs.readable).blob().then(blobToBase64);
24
27
  }
25
28
  async decompress(input) {
26
29
  await ensureCompressionStream();
30
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
27
31
  const bytes = Uint8Array.from(atob(input), c => c.charCodeAt(0));
28
32
  const cs = new DecompressionStream(this.algorithm);
29
33
  const writer = cs.writable.getWriter();
30
- writer.write(bytes);
31
- writer.close();
32
- return new Response(cs.readable).arrayBuffer().then(function (arrayBuffer) {
33
- return new TextDecoder().decode(arrayBuffer);
34
+ writer.ready
35
+ .then(() => writer.write(bytes))
36
+ .then(() => writer.close())
37
+ .catch(console.log);
38
+ return new Response(cs.readable).arrayBuffer().then(arrayBuffer => {
39
+ return decoder.decode(arrayBuffer);
34
40
  });
35
41
  }
36
42
  }
@@ -10,7 +10,7 @@ export default class SerializerChecksum extends SerializerV0 {
10
10
  enumerable: true,
11
11
  configurable: true,
12
12
  writable: true,
13
- value: 3
13
+ value: 4
14
14
  });
15
15
  }
16
16
  parseTile(_str) {
@@ -87,6 +87,8 @@ export default class SerializerChecksum extends SerializerV0 {
87
87
  : escape(String(instruction[config.field])
88
88
  .toLowerCase()
89
89
  .trim())));
90
+ case ConfigType.NullableInstrument:
91
+ return config.field + '='; // do not include instrument in checksum
90
92
  case ConfigType.Tile:
91
93
  case ConfigType.Grid:
92
94
  return (config.field +
@@ -2,7 +2,7 @@ import GridData from '../grid.js';
2
2
  import GridConnections from '../gridConnections.js';
3
3
  import TileData from '../tile.js';
4
4
  import { ConfigType, } from '../config.js';
5
- import { Color, DIRECTIONS, ORIENTATIONS, Orientation, directionToggle, orientationToggle, } from '../primitives.js';
5
+ import { Color, DIRECTIONS, ORIENTATIONS, Orientation, directionToggle, orientationToggle, INSTRUMENTS, } from '../primitives.js';
6
6
  import { array, escape, unescape } from '../dataHelper.js';
7
7
  import { allRules } from '../rules/index.js';
8
8
  import { allSymbols } from '../symbols/index.js';
@@ -54,7 +54,7 @@ export default class SerializerV0 extends SerializerBase {
54
54
  if (line.checkpoint)
55
55
  result.push('s');
56
56
  result.push(`r${line.rows
57
- .map(row => `v${row.velocity ?? ''}n${row.note ?? ''}`)
57
+ .map(row => `i${row.instrument ?? ''}v${row.velocity ?? ''}n${row.note ?? ''}`)
58
58
  .join(',')}`);
59
59
  return result.join('|');
60
60
  }
@@ -83,11 +83,14 @@ export default class SerializerV0 extends SerializerBase {
83
83
  break;
84
84
  case 'r':
85
85
  rows.push(...value.split(',').map(row => {
86
- const match = /^v([\d.]*?)n(.*)$/.exec(row);
86
+ const match = /^(?:i(\w*?))?v([\d.]*?)n(.*)$/.exec(row);
87
87
  if (!match)
88
- return new Row(null, null);
89
- const [, velocity, note] = match;
90
- return new Row(note === '' ? null : note, velocity === '' ? null : Number(velocity));
88
+ return new Row(null, null, null);
89
+ const [, instrument, velocity, note] = match;
90
+ return new Row(note === '' ? null : note, instrument === '' ||
91
+ !INSTRUMENTS.includes(instrument)
92
+ ? null
93
+ : instrument, velocity === '' ? null : Number(velocity));
91
94
  }));
92
95
  break;
93
96
  }
@@ -146,6 +149,12 @@ export default class SerializerV0 extends SerializerBase {
146
149
  escape(instruction[config.field] === null
147
150
  ? ''
148
151
  : escape(String(instruction[config.field]))));
152
+ case ConfigType.NullableInstrument:
153
+ return (config.field +
154
+ '=' +
155
+ escape(instruction[config.field] === null
156
+ ? ''
157
+ : String(instruction[config.field])));
149
158
  case ConfigType.Tile:
150
159
  case ConfigType.Shape:
151
160
  case ConfigType.Grid:
@@ -233,6 +242,11 @@ export default class SerializerV0 extends SerializerBase {
233
242
  ];
234
243
  case ConfigType.NullableNote:
235
244
  return [config.field, value === '' ? null : unescape(value)];
245
+ case ConfigType.NullableInstrument:
246
+ return [
247
+ config.field,
248
+ value === '' ? null : unescape(value),
249
+ ];
236
250
  case ConfigType.SolvePath:
237
251
  return [
238
252
  config.field,
@@ -16,6 +16,7 @@ import { instance as myopiaInstance } from '../../symbols/myopiaSymbol.js';
16
16
  import { instance as viewpointInstance } from '../../symbols/viewpointSymbol.js';
17
17
  import { instance as connectAllInstance } from '../../rules/connectAllRule.js';
18
18
  import EventIteratingSolver from '../eventIteratingSolver.js';
19
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
19
20
  ('vite-apply-code-mod');
20
21
  class BacktrackSolver extends EventIteratingSolver {
21
22
  constructor() {
@@ -17,6 +17,7 @@ import { instance as connectAllInstance } from '../../rules/connectAllRule.js';
17
17
  import EventIteratingSolver from '../eventIteratingSolver.js';
18
18
  import GridData from '../../grid.js';
19
19
  import { Color } from '../../primitives.js';
20
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
20
21
  ('vite-apply-code-mod');
21
22
  class CspuzSolver extends EventIteratingSolver {
22
23
  constructor() {
@@ -1,5 +1,6 @@
1
1
  import { instance as undercluedInstance } from '../../rules/undercluedRule.js';
2
2
  import EventIteratingSolver from '../eventIteratingSolver.js';
3
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
3
4
  ('vite-apply-code-mod');
4
5
  export default class UniversalSolver extends EventIteratingSolver {
5
6
  constructor() {
@@ -0,0 +1,15 @@
1
+ import GridData from './grid.js';
2
+ import { GridState } from './primitives.js';
3
+ export declare class GridValidator {
4
+ private worker;
5
+ private stateListeners;
6
+ private loadListeners;
7
+ private readonly validateGridDebounced;
8
+ readonly validateGrid: (grid: GridData, solution: GridData | null) => void;
9
+ private readonly notifyState;
10
+ readonly subscribeToState: (listener: (state: GridState) => void) => () => void;
11
+ private readonly notifyLoad;
12
+ readonly subscribeToLoad: (listener: () => void) => () => void;
13
+ readonly isLoading: () => boolean;
14
+ readonly delete: () => void;
15
+ }
@@ -0,0 +1,128 @@
1
+ import debounce from 'lodash/debounce.js';
2
+ import { Serializer } from './serializer/allSerializers.js';
3
+ import validateGrid from './validate.js';
4
+ const SYNC_VALIDATION_THRESHOLD = 10000;
5
+ export class GridValidator {
6
+ constructor() {
7
+ Object.defineProperty(this, "worker", {
8
+ enumerable: true,
9
+ configurable: true,
10
+ writable: true,
11
+ value: null
12
+ });
13
+ Object.defineProperty(this, "stateListeners", {
14
+ enumerable: true,
15
+ configurable: true,
16
+ writable: true,
17
+ value: new Set()
18
+ });
19
+ Object.defineProperty(this, "loadListeners", {
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true,
23
+ value: new Set()
24
+ });
25
+ Object.defineProperty(this, "validateGridDebounced", {
26
+ enumerable: true,
27
+ configurable: true,
28
+ writable: true,
29
+ value: debounce((grid, solution) => {
30
+ this.worker?.terminate();
31
+ this.worker = new Worker(new URL('./validateAsyncWorker.js', import.meta.url), { type: 'module' });
32
+ this.worker.onmessage = (event) => {
33
+ if (event.data) {
34
+ this.notifyState(event.data);
35
+ }
36
+ this.worker?.terminate();
37
+ this.worker = null;
38
+ this.notifyLoad();
39
+ };
40
+ this.worker.onmessageerror = (error) => {
41
+ console.error('Validation worker error:', error);
42
+ this.worker?.terminate();
43
+ this.worker = null;
44
+ this.notifyLoad();
45
+ };
46
+ this.worker.postMessage({
47
+ grid: Serializer.stringifyGrid(grid),
48
+ solution: solution ? Serializer.stringifyGrid(solution) : null,
49
+ });
50
+ this.notifyLoad();
51
+ }, 300, { leading: true, trailing: true })
52
+ });
53
+ Object.defineProperty(this, "validateGrid", {
54
+ enumerable: true,
55
+ configurable: true,
56
+ writable: true,
57
+ value: (grid, solution) => {
58
+ if (grid.width * grid.height <= SYNC_VALIDATION_THRESHOLD) {
59
+ // Synchronous validation for small grids
60
+ // to avoid the overhead of worker communication.
61
+ const state = validateGrid(grid, solution);
62
+ this.notifyState(state);
63
+ }
64
+ else {
65
+ this.validateGridDebounced(grid, solution);
66
+ }
67
+ }
68
+ });
69
+ Object.defineProperty(this, "notifyState", {
70
+ enumerable: true,
71
+ configurable: true,
72
+ writable: true,
73
+ value: (state) => {
74
+ this.stateListeners.forEach(listener => listener(state));
75
+ }
76
+ });
77
+ Object.defineProperty(this, "subscribeToState", {
78
+ enumerable: true,
79
+ configurable: true,
80
+ writable: true,
81
+ value: (listener) => {
82
+ this.stateListeners.add(listener);
83
+ return () => {
84
+ this.stateListeners.delete(listener);
85
+ };
86
+ }
87
+ });
88
+ Object.defineProperty(this, "notifyLoad", {
89
+ enumerable: true,
90
+ configurable: true,
91
+ writable: true,
92
+ value: () => {
93
+ this.loadListeners.forEach(listener => listener());
94
+ }
95
+ });
96
+ Object.defineProperty(this, "subscribeToLoad", {
97
+ enumerable: true,
98
+ configurable: true,
99
+ writable: true,
100
+ value: (listener) => {
101
+ this.loadListeners.add(listener);
102
+ return () => {
103
+ this.loadListeners.delete(listener);
104
+ };
105
+ }
106
+ });
107
+ Object.defineProperty(this, "isLoading", {
108
+ enumerable: true,
109
+ configurable: true,
110
+ writable: true,
111
+ value: () => {
112
+ return this.worker !== null;
113
+ }
114
+ });
115
+ Object.defineProperty(this, "delete", {
116
+ enumerable: true,
117
+ configurable: true,
118
+ writable: true,
119
+ value: () => {
120
+ if (this.worker) {
121
+ this.worker.terminate();
122
+ this.worker = null;
123
+ }
124
+ this.stateListeners.clear();
125
+ }
126
+ });
127
+ }
128
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import { Serializer } from './serializer/allSerializers.js';
2
+ import validateGrid from './validate.js';
3
+ onmessage = e => {
4
+ const data = e.data;
5
+ const grid = Serializer.parseGrid(data.grid);
6
+ const solution = data.solution ? Serializer.parseGrid(data.solution) : null;
7
+ const state = validateGrid(grid, solution);
8
+ postMessage(state);
9
+ };
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ import GridData, { NEIGHBOR_OFFSETS } from './data/grid.js';
13
13
  import GridConnections from './data/gridConnections.js';
14
14
  import GridZones from './data/gridZones.js';
15
15
  import Instruction from './data/instruction.js';
16
- import { COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, PuzzleType, State, WRAPPINGS, Wrapping, directionToggle, orientationToggle } from './data/primitives.js';
16
+ import { COMPARISONS, Color, Comparison, DIRECTIONS, DRUM_SAMPLES, Direction, INSTRUMENTS, Instrument, MajorRule, Mode, ORIENTATIONS, Orientation, PuzzleType, State, WRAPPINGS, Wrapping, directionToggle, isDrumSample, orientationToggle } from './data/primitives.js';
17
17
  import { MetadataSchema, PuzzleSchema, getPuzzleTypes, puzzleEquals, validatePuzzleChecklist } from './data/puzzle.js';
18
18
  import BanPatternRule from './data/rules/banPatternRule.js';
19
19
  import CellCountPerZoneRule from './data/rules/cellCountPerZoneRule.js';
@@ -113,4 +113,5 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
113
113
  import TileData from './data/tile.js';
114
114
  import TileConnections from './data/tileConnections.js';
115
115
  import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
116
- export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGetTile, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, PuzzleType, State, WRAPPINGS, Wrapping, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, getPuzzleTypes, puzzleEquals, validatePuzzleChecklist, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, ContainsShapeRule, CustomRule, DifferentCountPerZoneRule, ForesightRule, allRules, LyingSymbolRule, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameCountPerZoneRule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, WrapAroundRule, Serializer, Compressor, ChecksumCompressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerChecksum, SerializerV0, OFFSETS, orientationChars, getShapeVariants, normalizeShape, positionsToShape, sanitizePatternGrid, shapeEquals, tilesToShape, allSolvers, AutoSolver, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, FocusBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, CspuzSolver, gridToJson, EventIteratingSolver, Solver, UniversalSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, FocusSymbol, GalaxySymbol, HiddenSymbol, HouseSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
116
+ import { GridValidator } from './data/validateAsync.js';
117
+ export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGetTile, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, DRUM_SAMPLES, Direction, INSTRUMENTS, Instrument, MajorRule, Mode, ORIENTATIONS, Orientation, PuzzleType, State, WRAPPINGS, Wrapping, directionToggle, isDrumSample, orientationToggle, MetadataSchema, PuzzleSchema, getPuzzleTypes, puzzleEquals, validatePuzzleChecklist, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, ContainsShapeRule, CustomRule, DifferentCountPerZoneRule, ForesightRule, allRules, LyingSymbolRule, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameCountPerZoneRule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, WrapAroundRule, Serializer, Compressor, ChecksumCompressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerChecksum, SerializerV0, OFFSETS, orientationChars, getShapeVariants, normalizeShape, positionsToShape, sanitizePatternGrid, shapeEquals, tilesToShape, allSolvers, AutoSolver, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, FocusBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, CspuzSolver, gridToJson, EventIteratingSolver, Solver, UniversalSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, FocusSymbol, GalaxySymbol, HiddenSymbol, HouseSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, GridValidator, };
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ import GridData, { NEIGHBOR_OFFSETS } from './data/grid.js';
16
16
  import GridConnections from './data/gridConnections.js';
17
17
  import GridZones from './data/gridZones.js';
18
18
  import Instruction from './data/instruction.js';
19
- import { COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, PuzzleType, State, WRAPPINGS, Wrapping, directionToggle, orientationToggle } from './data/primitives.js';
19
+ import { COMPARISONS, Color, Comparison, DIRECTIONS, DRUM_SAMPLES, Direction, INSTRUMENTS, Instrument, MajorRule, Mode, ORIENTATIONS, Orientation, PuzzleType, State, WRAPPINGS, Wrapping, directionToggle, isDrumSample, orientationToggle } from './data/primitives.js';
20
20
  import { MetadataSchema, PuzzleSchema, getPuzzleTypes, puzzleEquals, validatePuzzleChecklist } from './data/puzzle.js';
21
21
  import BanPatternRule from './data/rules/banPatternRule.js';
22
22
  import CellCountPerZoneRule from './data/rules/cellCountPerZoneRule.js';
@@ -116,4 +116,5 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
116
116
  import TileData from './data/tile.js';
117
117
  import TileConnections from './data/tileConnections.js';
118
118
  import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
119
- export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGetTile, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, PuzzleType, State, WRAPPINGS, Wrapping, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, getPuzzleTypes, puzzleEquals, validatePuzzleChecklist, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, ContainsShapeRule, CustomRule, DifferentCountPerZoneRule, ForesightRule, allRules, LyingSymbolRule, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameCountPerZoneRule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, WrapAroundRule, Serializer, Compressor, ChecksumCompressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerChecksum, SerializerV0, OFFSETS, orientationChars, getShapeVariants, normalizeShape, positionsToShape, sanitizePatternGrid, shapeEquals, tilesToShape, allSolvers, AutoSolver, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, FocusBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, CspuzSolver, gridToJson, EventIteratingSolver, Solver, UniversalSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, FocusSymbol, GalaxySymbol, HiddenSymbol, HouseSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
119
+ import { GridValidator } from './data/validateAsync.js';
120
+ export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGetTile, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, DRUM_SAMPLES, Direction, INSTRUMENTS, Instrument, MajorRule, Mode, ORIENTATIONS, Orientation, PuzzleType, State, WRAPPINGS, Wrapping, directionToggle, isDrumSample, orientationToggle, MetadataSchema, PuzzleSchema, getPuzzleTypes, puzzleEquals, validatePuzzleChecklist, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, ContainsShapeRule, CustomRule, DifferentCountPerZoneRule, ForesightRule, allRules, LyingSymbolRule, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameCountPerZoneRule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, WrapAroundRule, Serializer, Compressor, ChecksumCompressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerChecksum, SerializerV0, OFFSETS, orientationChars, getShapeVariants, normalizeShape, positionsToShape, sanitizePatternGrid, shapeEquals, tilesToShape, allSolvers, AutoSolver, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, FocusBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, CspuzSolver, gridToJson, EventIteratingSolver, Solver, UniversalSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, FocusSymbol, GalaxySymbol, HiddenSymbol, HouseSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, GridValidator, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logic-pad/core",
3
- "version": "0.19.1",
3
+ "version": "0.21.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -54,6 +54,7 @@
54
54
  "compression-streams-polyfill": "^0.1.7",
55
55
  "event-iterator": "^2.0.0",
56
56
  "grilops": "^0.1.2",
57
+ "lodash": "^4.17.21",
57
58
  "logic-pad-solver-core": "^0.1.2",
58
59
  "z3-solver": "^4.13.0",
59
60
  "zod": "^4.0.17"
@@ -61,6 +62,7 @@
61
62
  "devDependencies": {
62
63
  "@types/bun": "^1.2.20",
63
64
  "@types/glob": "^9.0.0",
65
+ "@types/lodash": "^4.17.20",
64
66
  "dts-bundle-generator": "^9.5.1",
65
67
  "fast-glob": "^3.3.3",
66
68
  "prettier": "^3.6.2",
@@ -70,4 +72,4 @@
70
72
  "trustedDependencies": [
71
73
  "esbuild"
72
74
  ]
73
- }
75
+ }