chess2img 0.2.0 → 0.2.2
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 +43 -4
- package/dist/index.cjs +166 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +166 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,7 +89,25 @@ const png = await renderChess({
|
|
|
89
89
|
await writeFile("board.png", png);
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
### Coordinates
|
|
92
|
+
### Automatic Coordinates
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { writeFile } from "node:fs/promises";
|
|
96
|
+
import { renderChess } from "chess2img";
|
|
97
|
+
|
|
98
|
+
const png = await renderChess({
|
|
99
|
+
fen: "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1",
|
|
100
|
+
size: 480,
|
|
101
|
+
style: "cburnett",
|
|
102
|
+
coordinates: true,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
await writeFile("board-with-auto-coordinates.png", png);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`coordinates: true` chooses `border` mode when `borderSize > 0`, otherwise it falls back to `inside` mode.
|
|
109
|
+
|
|
110
|
+
### Border Coordinates
|
|
93
111
|
|
|
94
112
|
```ts
|
|
95
113
|
import { writeFile } from "node:fs/promises";
|
|
@@ -102,11 +120,28 @@ const png = await renderChess({
|
|
|
102
120
|
borderSize: 24,
|
|
103
121
|
coordinates: {
|
|
104
122
|
enabled: true,
|
|
123
|
+
position: "border",
|
|
105
124
|
color: "#333",
|
|
106
125
|
},
|
|
107
126
|
});
|
|
108
127
|
|
|
109
|
-
await writeFile("board-with-coordinates.png", png);
|
|
128
|
+
await writeFile("board-with-border-coordinates.png", png);
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Inside Coordinates
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { writeFile } from "node:fs/promises";
|
|
135
|
+
import { renderChess } from "chess2img";
|
|
136
|
+
|
|
137
|
+
const png = await renderChess({
|
|
138
|
+
fen: "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1",
|
|
139
|
+
size: 480,
|
|
140
|
+
style: "cburnett",
|
|
141
|
+
coordinates: "inside",
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
await writeFile("board-with-inside-coordinates.png", png);
|
|
110
145
|
```
|
|
111
146
|
|
|
112
147
|
### Class API
|
|
@@ -227,12 +262,16 @@ Semantics:
|
|
|
227
262
|
- `style`: built-in theme alias
|
|
228
263
|
- `theme`: built-in theme name, registered custom theme name, or inline `ThemeDefinition`
|
|
229
264
|
- `highlightSquares`: array of algebraic squares such as `["e4", "d5"]`
|
|
230
|
-
- `coordinates`: `boolean` or `{ enabled?: boolean; color?: string }`
|
|
265
|
+
- `coordinates`: `boolean`, `"border"`, `"inside"`, or `{ enabled?: boolean; position?: "border" | "inside"; color?: string }`
|
|
231
266
|
- `colors.lightSquare`
|
|
232
267
|
- `colors.darkSquare`
|
|
233
268
|
- `colors.highlight`
|
|
234
269
|
|
|
235
|
-
`coordinates:
|
|
270
|
+
`coordinates: false` or omitting the option disables labels. `coordinates: true` enables labels and chooses `border` mode when `borderSize > 0`, otherwise `inside` mode. Explicit `coordinates: "inside"` is always valid. Explicit `coordinates: "border"` requires `borderSize > 0` and throws `ValidationError` otherwise.
|
|
271
|
+
|
|
272
|
+
Inside coordinates use automatic light/dark contrast by default, similar to chess.com. If `coordinates.color` is provided, that exact color is used instead. Border coordinates keep a single-color label style with `#333` as the default.
|
|
273
|
+
|
|
274
|
+
At very small valid sizes, the renderer suppresses coordinates when they cannot fit legibly in the available border band or edge-square area.
|
|
236
275
|
|
|
237
276
|
### Errors
|
|
238
277
|
|
package/dist/index.cjs
CHANGED
|
@@ -184,16 +184,37 @@ function validateBoardColors(colors) {
|
|
|
184
184
|
function isCoordinatesOptions(value) {
|
|
185
185
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
186
186
|
}
|
|
187
|
-
function
|
|
187
|
+
function isCoordinatesPosition(value) {
|
|
188
|
+
return value === "border" || value === "inside";
|
|
189
|
+
}
|
|
190
|
+
function validateCoordinatesOption(coordinates, borderSize) {
|
|
188
191
|
if (coordinates === void 0 || typeof coordinates === "boolean") {
|
|
189
192
|
return;
|
|
190
193
|
}
|
|
194
|
+
if (isCoordinatesPosition(coordinates)) {
|
|
195
|
+
if (coordinates === "border" && borderSize === 0) {
|
|
196
|
+
throw new ValidationError(
|
|
197
|
+
"coordinates position 'border' requires borderSize > 0"
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
191
202
|
if (!isCoordinatesOptions(coordinates)) {
|
|
192
|
-
throw new ValidationError(
|
|
203
|
+
throw new ValidationError(
|
|
204
|
+
"coordinates must be false, true, 'border', 'inside', or an options object"
|
|
205
|
+
);
|
|
193
206
|
}
|
|
194
207
|
if (coordinates.enabled !== void 0 && typeof coordinates.enabled !== "boolean") {
|
|
195
208
|
throw new ValidationError("coordinates.enabled must be a boolean");
|
|
196
209
|
}
|
|
210
|
+
if (coordinates.position !== void 0 && !isCoordinatesPosition(coordinates.position)) {
|
|
211
|
+
throw new ValidationError("coordinates.position must be 'border' or 'inside'");
|
|
212
|
+
}
|
|
213
|
+
if (coordinates.enabled !== false && coordinates.position === "border" && borderSize === 0) {
|
|
214
|
+
throw new ValidationError(
|
|
215
|
+
"coordinates position 'border' requires borderSize > 0"
|
|
216
|
+
);
|
|
217
|
+
}
|
|
197
218
|
if (coordinates.color !== void 0) {
|
|
198
219
|
validateColorString(coordinates.color, "coordinates.color");
|
|
199
220
|
}
|
|
@@ -295,16 +316,54 @@ function createBoardGeometry({
|
|
|
295
316
|
);
|
|
296
317
|
const displayedFiles = flipped ? [...FILES].reverse() : [...FILES];
|
|
297
318
|
const displayedRanks = flipped ? [...RANKS].reverse() : [...RANKS];
|
|
298
|
-
const
|
|
319
|
+
const bottomEdgeRank = flipped ? "8" : "1";
|
|
320
|
+
const leftEdgeFile = flipped ? "h" : "a";
|
|
321
|
+
const borderFileLabels = borderSize ? displayedFiles.map((file, fileIndex) => ({
|
|
299
322
|
text: file,
|
|
300
323
|
x: boardX + fileIndex * squareSize + squareSize / 2,
|
|
301
|
-
y: boardOuterY + boardOuterSize - borderSize / 2
|
|
324
|
+
y: boardOuterY + boardOuterSize - borderSize / 2,
|
|
325
|
+
square: `${file}${bottomEdgeRank}`,
|
|
326
|
+
textAlign: "center",
|
|
327
|
+
textBaseline: "middle"
|
|
302
328
|
})) : [];
|
|
303
|
-
const
|
|
329
|
+
const borderRankLabels = borderSize ? displayedRanks.map((rank, rankIndex) => ({
|
|
304
330
|
text: rank,
|
|
305
331
|
x: boardOuterX + borderSize / 2,
|
|
306
|
-
y: boardY + rankIndex * squareSize + squareSize / 2
|
|
332
|
+
y: boardY + rankIndex * squareSize + squareSize / 2,
|
|
333
|
+
square: `${leftEdgeFile}${rank}`,
|
|
334
|
+
textAlign: "center",
|
|
335
|
+
textBaseline: "middle"
|
|
307
336
|
})) : [];
|
|
337
|
+
const insideFileInsetX = squareSize * 0.14;
|
|
338
|
+
const insideFileInsetY = squareSize * 0.1;
|
|
339
|
+
const insideRankInsetX = squareSize * 0.14;
|
|
340
|
+
const insideRankInsetY = squareSize * 0.1;
|
|
341
|
+
const insideLabelMaxWidth = squareSize * 0.26;
|
|
342
|
+
const insideLabelMaxHeight = squareSize * 0.24;
|
|
343
|
+
const insideFileLabels = displayedFiles.map((file) => {
|
|
344
|
+
const square = `${file}${bottomEdgeRank}`;
|
|
345
|
+
const squareGeometry = squares[square];
|
|
346
|
+
return {
|
|
347
|
+
text: file,
|
|
348
|
+
x: squareGeometry.x + squareGeometry.size - insideFileInsetX,
|
|
349
|
+
y: squareGeometry.y + squareGeometry.size - insideFileInsetY,
|
|
350
|
+
square,
|
|
351
|
+
textAlign: "right",
|
|
352
|
+
textBaseline: "bottom"
|
|
353
|
+
};
|
|
354
|
+
});
|
|
355
|
+
const insideRankLabels = displayedRanks.map((rank) => {
|
|
356
|
+
const square = `${leftEdgeFile}${rank}`;
|
|
357
|
+
const squareGeometry = squares[square];
|
|
358
|
+
return {
|
|
359
|
+
text: rank,
|
|
360
|
+
x: squareGeometry.x + insideRankInsetX,
|
|
361
|
+
y: squareGeometry.y + insideRankInsetY,
|
|
362
|
+
square,
|
|
363
|
+
textAlign: "left",
|
|
364
|
+
textBaseline: "top"
|
|
365
|
+
};
|
|
366
|
+
});
|
|
308
367
|
return {
|
|
309
368
|
imageWidth: left + size + right,
|
|
310
369
|
imageHeight: top + size + bottom,
|
|
@@ -316,8 +375,16 @@ function createBoardGeometry({
|
|
|
316
375
|
boardX,
|
|
317
376
|
boardY,
|
|
318
377
|
boardSize,
|
|
319
|
-
|
|
320
|
-
|
|
378
|
+
borderFileLabels,
|
|
379
|
+
borderRankLabels,
|
|
380
|
+
insideFileLabels,
|
|
381
|
+
insideRankLabels,
|
|
382
|
+
insideFileInsetX,
|
|
383
|
+
insideFileInsetY,
|
|
384
|
+
insideRankInsetX,
|
|
385
|
+
insideRankInsetY,
|
|
386
|
+
insideLabelMaxWidth,
|
|
387
|
+
insideLabelMaxHeight,
|
|
321
388
|
squares
|
|
322
389
|
};
|
|
323
390
|
}
|
|
@@ -421,6 +488,9 @@ var MIN_COORDINATE_FONT_SIZE = 8;
|
|
|
421
488
|
var MAX_FILE_LABEL_WIDTH_RATIO = 0.75;
|
|
422
489
|
var MAX_RANK_LABEL_WIDTH_RATIO = 0.7;
|
|
423
490
|
var MAX_LABEL_HEIGHT_RATIO = 0.7;
|
|
491
|
+
var INSIDE_COORDINATE_MAX_FONT_RATIO = 0.34;
|
|
492
|
+
var INSIDE_LIGHT_LABEL_COLOR = "rgba(255,255,255,0.6)";
|
|
493
|
+
var INSIDE_DARK_LABEL_COLOR = "rgba(0,0,0,0.45)";
|
|
424
494
|
function isDarkSquare(square) {
|
|
425
495
|
const fileIndex = square.charCodeAt(0) - 97;
|
|
426
496
|
const rankNumber = Number(square[1]);
|
|
@@ -436,22 +506,25 @@ async function getPieceRaster(themeName, pieceKey, asset, squareSize) {
|
|
|
436
506
|
pieceRasterCache.set(cacheKey, raster);
|
|
437
507
|
return raster;
|
|
438
508
|
}
|
|
439
|
-
function
|
|
440
|
-
if (
|
|
441
|
-
return;
|
|
509
|
+
function resolveInsideLabelColor(request, square) {
|
|
510
|
+
if (request.coordinates.color) {
|
|
511
|
+
return request.coordinates.color;
|
|
442
512
|
}
|
|
513
|
+
return isDarkSquare(square) ? INSIDE_LIGHT_LABEL_COLOR : INSIDE_DARK_LABEL_COLOR;
|
|
514
|
+
}
|
|
515
|
+
function resolveBorderCoordinateFontSize(context, geometry) {
|
|
443
516
|
const maxFontSize = Math.floor(
|
|
444
517
|
Math.min(geometry.squareSize * 0.6, geometry.borderSize * 0.65)
|
|
445
518
|
);
|
|
446
519
|
let fontSize = null;
|
|
447
520
|
for (let candidate = maxFontSize; candidate >= MIN_COORDINATE_FONT_SIZE; candidate -= 1) {
|
|
448
521
|
context.font = `${candidate}px sans-serif`;
|
|
449
|
-
const filesFit = geometry.
|
|
522
|
+
const filesFit = geometry.borderFileLabels.every((label) => {
|
|
450
523
|
const metrics = context.measureText(label.text);
|
|
451
524
|
const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
|
|
452
525
|
return metrics.width <= geometry.squareSize * MAX_FILE_LABEL_WIDTH_RATIO && textHeight <= geometry.borderSize * MAX_LABEL_HEIGHT_RATIO;
|
|
453
526
|
});
|
|
454
|
-
const ranksFit = geometry.
|
|
527
|
+
const ranksFit = geometry.borderRankLabels.every((label) => {
|
|
455
528
|
const metrics = context.measureText(label.text);
|
|
456
529
|
const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
|
|
457
530
|
return metrics.width <= geometry.borderSize * MAX_RANK_LABEL_WIDTH_RATIO && textHeight <= geometry.squareSize * MAX_LABEL_HEIGHT_RATIO;
|
|
@@ -461,20 +534,80 @@ function drawCoordinates(context, request, geometry) {
|
|
|
461
534
|
break;
|
|
462
535
|
}
|
|
463
536
|
}
|
|
537
|
+
return fontSize;
|
|
538
|
+
}
|
|
539
|
+
function resolveInsideCoordinateFontSize(context, geometry) {
|
|
540
|
+
const maxFontSize = Math.floor(
|
|
541
|
+
geometry.squareSize * INSIDE_COORDINATE_MAX_FONT_RATIO
|
|
542
|
+
);
|
|
543
|
+
let fontSize = null;
|
|
544
|
+
for (let candidate = maxFontSize; candidate >= MIN_COORDINATE_FONT_SIZE; candidate -= 1) {
|
|
545
|
+
context.font = `${candidate}px sans-serif`;
|
|
546
|
+
const filesFit = geometry.insideFileLabels.every((label) => {
|
|
547
|
+
const metrics = context.measureText(label.text);
|
|
548
|
+
const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
|
|
549
|
+
return metrics.width <= geometry.insideLabelMaxWidth && textHeight <= geometry.insideLabelMaxHeight;
|
|
550
|
+
});
|
|
551
|
+
const ranksFit = geometry.insideRankLabels.every((label) => {
|
|
552
|
+
const metrics = context.measureText(label.text);
|
|
553
|
+
const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
|
|
554
|
+
return metrics.width <= geometry.insideLabelMaxWidth && textHeight <= geometry.insideLabelMaxHeight;
|
|
555
|
+
});
|
|
556
|
+
if (filesFit && ranksFit) {
|
|
557
|
+
fontSize = candidate;
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return fontSize;
|
|
562
|
+
}
|
|
563
|
+
function drawBorderCoordinates(context, request, geometry) {
|
|
564
|
+
if (geometry.borderSize === 0) {
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
const fontSize = resolveBorderCoordinateFontSize(context, geometry);
|
|
464
568
|
if (fontSize === null) {
|
|
465
569
|
return;
|
|
466
570
|
}
|
|
467
|
-
context.fillStyle = request.coordinates.color;
|
|
571
|
+
context.fillStyle = request.coordinates.color ?? "#333";
|
|
468
572
|
context.font = `${fontSize}px sans-serif`;
|
|
469
573
|
context.textAlign = "center";
|
|
470
574
|
context.textBaseline = "middle";
|
|
471
|
-
for (const label of geometry.
|
|
575
|
+
for (const label of geometry.borderFileLabels) {
|
|
472
576
|
context.fillText(label.text, label.x, label.y);
|
|
473
577
|
}
|
|
474
|
-
for (const label of geometry.
|
|
578
|
+
for (const label of geometry.borderRankLabels) {
|
|
475
579
|
context.fillText(label.text, label.x, label.y);
|
|
476
580
|
}
|
|
477
581
|
}
|
|
582
|
+
function drawInsideCoordinates(context, request, geometry) {
|
|
583
|
+
const fontSize = resolveInsideCoordinateFontSize(context, geometry);
|
|
584
|
+
if (fontSize === null) {
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
context.font = `${fontSize}px sans-serif`;
|
|
588
|
+
for (const label of geometry.insideFileLabels) {
|
|
589
|
+
context.fillStyle = resolveInsideLabelColor(request, label.square);
|
|
590
|
+
context.textAlign = label.textAlign;
|
|
591
|
+
context.textBaseline = label.textBaseline;
|
|
592
|
+
context.fillText(label.text, label.x, label.y);
|
|
593
|
+
}
|
|
594
|
+
for (const label of geometry.insideRankLabels) {
|
|
595
|
+
context.fillStyle = resolveInsideLabelColor(request, label.square);
|
|
596
|
+
context.textAlign = label.textAlign;
|
|
597
|
+
context.textBaseline = label.textBaseline;
|
|
598
|
+
context.fillText(label.text, label.x, label.y);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
function drawCoordinates(context, request, geometry) {
|
|
602
|
+
if (!request.coordinates.enabled) {
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
if (request.coordinates.position === "border") {
|
|
606
|
+
drawBorderCoordinates(context, request, geometry);
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
drawInsideCoordinates(context, request, geometry);
|
|
610
|
+
}
|
|
478
611
|
var CanvasPngRenderer = class {
|
|
479
612
|
async render(request) {
|
|
480
613
|
try {
|
|
@@ -695,7 +828,7 @@ var DEFAULT_COLORS = {
|
|
|
695
828
|
};
|
|
696
829
|
var DEFAULT_COORDINATES = {
|
|
697
830
|
enabled: false,
|
|
698
|
-
|
|
831
|
+
position: "inside"
|
|
699
832
|
};
|
|
700
833
|
function normalizeColors(colors) {
|
|
701
834
|
return {
|
|
@@ -704,19 +837,30 @@ function normalizeColors(colors) {
|
|
|
704
837
|
highlight: colors?.highlight ?? DEFAULT_COLORS.highlight
|
|
705
838
|
};
|
|
706
839
|
}
|
|
707
|
-
function normalizeCoordinates(coordinates) {
|
|
840
|
+
function normalizeCoordinates(coordinates, borderSize) {
|
|
708
841
|
if (coordinates === void 0 || coordinates === false) {
|
|
709
842
|
return { ...DEFAULT_COORDINATES };
|
|
710
843
|
}
|
|
844
|
+
const defaultPosition = borderSize > 0 ? "border" : "inside";
|
|
711
845
|
if (coordinates === true) {
|
|
712
846
|
return {
|
|
713
847
|
enabled: true,
|
|
714
|
-
|
|
848
|
+
position: defaultPosition,
|
|
849
|
+
color: defaultPosition === "border" ? "#333" : void 0
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
if (coordinates === "border" || coordinates === "inside") {
|
|
853
|
+
return {
|
|
854
|
+
enabled: true,
|
|
855
|
+
position: coordinates,
|
|
856
|
+
color: coordinates === "border" ? "#333" : void 0
|
|
715
857
|
};
|
|
716
858
|
}
|
|
859
|
+
const position = coordinates.position ?? defaultPosition;
|
|
717
860
|
return {
|
|
718
861
|
enabled: coordinates.enabled ?? true,
|
|
719
|
-
|
|
862
|
+
position,
|
|
863
|
+
color: coordinates.color ?? (position === "border" ? "#333" : void 0)
|
|
720
864
|
};
|
|
721
865
|
}
|
|
722
866
|
function normalizeRenderInputs(options) {
|
|
@@ -726,7 +870,7 @@ function normalizeRenderInputs(options) {
|
|
|
726
870
|
size
|
|
727
871
|
);
|
|
728
872
|
validateBoardColors(options.colors);
|
|
729
|
-
validateCoordinatesOption(options.coordinates);
|
|
873
|
+
validateCoordinatesOption(options.coordinates, borderSize);
|
|
730
874
|
return {
|
|
731
875
|
size,
|
|
732
876
|
padding: normalizePadding(options.padding ?? DEFAULT_PADDING),
|
|
@@ -738,7 +882,7 @@ function normalizeRenderInputs(options) {
|
|
|
738
882
|
}),
|
|
739
883
|
highlightSquares: normalizeHighlights(options.highlightSquares ?? []),
|
|
740
884
|
colors: normalizeColors(options.colors),
|
|
741
|
-
coordinates: normalizeCoordinates(options.coordinates)
|
|
885
|
+
coordinates: normalizeCoordinates(options.coordinates, borderSize)
|
|
742
886
|
};
|
|
743
887
|
}
|
|
744
888
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types/errors.ts","../src/core/parsers.ts","../src/core/board.ts","../src/core/validators.ts","../src/core/highlights.ts","../src/render/canvas-renderer.ts","../src/core/geometry.ts","../src/render/asset-cache.ts","../src/render/rasterizer.ts","../src/utils/io.ts","../src/themes/builtins.ts","../src/themes/validation.ts","../src/themes/registry.ts","../src/themes/resolver.ts","../src/utils/normalization.ts","../src/api/class-api.ts","../src/api/functional-api.ts"],"sourcesContent":["export * from \"./types/errors\";\nexport * from \"./types/types\";\nexport * from \"./api/class-api\";\nexport * from \"./api/functional-api\";\nexport * from \"./api/theme-api\";\n","export class ValidationError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"ValidationError\";\n }\n}\n\nexport class ParseError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"ParseError\";\n }\n}\n\nexport class ThemeError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"ThemeError\";\n }\n}\n\nexport class RenderError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"RenderError\";\n }\n}\n\nexport class IOError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"IOError\";\n }\n}\n","import { Chess } from \"chess.js\";\nimport type { BoardArray, BoardCell, PieceKey } from \"../types/types\";\nimport { ParseError, ValidationError } from \"../types/errors\";\nimport { createEmptyBoardPosition, FILES } from \"./board\";\nimport { validateBoardArray } from \"./validators\";\n\nconst PIECE_SYMBOL_TO_KEY: Record<string, PieceKey> = {\n K: \"wK\",\n Q: \"wQ\",\n R: \"wR\",\n B: \"wB\",\n N: \"wN\",\n P: \"wP\",\n k: \"bK\",\n q: \"bQ\",\n r: \"bR\",\n b: \"bB\",\n n: \"bN\",\n p: \"bP\",\n};\n\nfunction chessBoardToBoardArray(board: ReturnType<Chess[\"board\"]>): BoardArray {\n return board.map((rank) =>\n rank.map((piece): BoardCell => {\n if (!piece) {\n return null;\n }\n\n return piece.color === \"w\" ? piece.type.toUpperCase() : piece.type;\n }),\n );\n}\n\nexport function parseFEN(fen: string) {\n const chess = new Chess();\n\n try {\n chess.load(fen);\n } catch (error) {\n throw new ParseError(\"Invalid FEN\", { cause: error });\n }\n\n return parseBoardArray(chessBoardToBoardArray(chess.board()));\n}\n\nexport function parsePGN(pgn: string) {\n const chess = new Chess();\n\n try {\n chess.loadPgn(pgn);\n } catch (error) {\n throw new ParseError(\"Invalid PGN\", { cause: error });\n }\n\n return parseBoardArray(chessBoardToBoardArray(chess.board()));\n}\n\nexport function parseBoardArray(board: BoardArray) {\n const validatedBoard = validateBoardArray(board);\n const position = createEmptyBoardPosition();\n\n validatedBoard.forEach((rank, rankIndex) => {\n rank.forEach((cell, fileIndex) => {\n if (cell === null) {\n return;\n }\n\n const pieceKey = PIECE_SYMBOL_TO_KEY[cell];\n\n if (!pieceKey) {\n throw new ValidationError(`Invalid board piece: ${cell}`);\n }\n\n const square = `${FILES[fileIndex]}${8 - rankIndex}` as keyof typeof position.squares;\n position.squares[square] = pieceKey;\n });\n });\n\n return position;\n}\n","import type { PieceKey, Square } from \"../types/types\";\n\nexport const FILES = [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"] as const;\nexport const RANKS = [\"8\", \"7\", \"6\", \"5\", \"4\", \"3\", \"2\", \"1\"] as const;\n\nexport const SQUARES: Square[] = RANKS.flatMap((rank) =>\n FILES.map((file) => `${file}${rank}`),\n);\n\nexport interface BoardPosition {\n squares: Record<Square, PieceKey | null>;\n}\n\nexport function createEmptyBoardPosition(): BoardPosition {\n return {\n squares: Object.fromEntries(\n SQUARES.map((square) => [square, null]),\n ) as Record<Square, PieceKey | null>,\n };\n}\n","import { createCanvas } from \"canvas\";\nimport type {\n BoardArray,\n BoardCell,\n BoardColors,\n CoordinatesOptions,\n Padding,\n Square,\n} from \"../types/types\";\nimport { ValidationError } from \"../types/errors\";\n\nconst SQUARE_PATTERN = /^[a-h][1-8]$/;\nconst PIECE_PATTERN = /^[prnbqkPRNBQK]$/;\nconst BUILT_IN_THEME_PATTERN = /^(merida|alpha|cburnett|cheq|leipzig)$/;\nconst colorValidationContext = createCanvas(1, 1).getContext(\"2d\");\n\nexport function validateSize(size: number): number {\n if (!Number.isFinite(size) || size <= 0) {\n throw new ValidationError(`Invalid board size: ${size}`);\n }\n\n return Math.round(size);\n}\n\nexport function normalizePadding(padding?: number[] | Padding): Padding {\n const candidate = padding ?? [0, 0, 0, 0];\n\n if (\n !Array.isArray(candidate) ||\n candidate.length !== 4 ||\n candidate.some((value) => !Number.isFinite(value) || value < 0)\n ) {\n throw new ValidationError(\"Padding must be a 4-item array of non-negative numbers\");\n }\n\n return [\n Math.round(candidate[0]),\n Math.round(candidate[1]),\n Math.round(candidate[2]),\n Math.round(candidate[3]),\n ];\n}\n\nexport function validateSquare(square: string): Square {\n const normalized = square.trim().toLowerCase();\n\n if (!SQUARE_PATTERN.test(normalized)) {\n throw new ValidationError(`Invalid square: ${square}`);\n }\n\n return normalized;\n}\n\nexport function validateBoardCell(cell: BoardCell): BoardCell {\n if (cell === null || cell === \"\" || cell === \" \") {\n return null;\n }\n\n if (typeof cell !== \"string\" || !PIECE_PATTERN.test(cell)) {\n throw new ValidationError(`Invalid board piece: ${String(cell)}`);\n }\n\n return cell;\n}\n\nexport function validateBoardArray(board: BoardArray): BoardArray {\n if (!Array.isArray(board) || board.length !== 8) {\n throw new ValidationError(\"Board array must have exactly 8 ranks\");\n }\n\n return board.map((rank, rankIndex) => {\n if (!Array.isArray(rank) || rank.length !== 8) {\n throw new ValidationError(`Board rank ${rankIndex} must contain exactly 8 files`);\n }\n\n return rank.map(validateBoardCell);\n });\n}\n\nexport function validateStyleName(style: string): string {\n const normalized = style.trim().toLowerCase();\n\n if (!BUILT_IN_THEME_PATTERN.test(normalized)) {\n throw new ValidationError(`Unknown built-in style: ${style}`);\n }\n\n return normalized;\n}\n\nexport function validateThemeName(name: string): string {\n const normalized = name.trim().toLowerCase();\n\n if (!/^[a-z0-9-]+$/.test(normalized)) {\n throw new ValidationError(`Invalid theme name: ${name}`);\n }\n\n return normalized;\n}\n\nexport function validateBorderSize(borderSize: number, size: number): number {\n const normalizedSize = validateSize(size);\n const normalizedBorderSize = Math.round(borderSize);\n const maxBorderSize = Math.floor(normalizedSize / 8);\n\n if (!Number.isFinite(borderSize) || normalizedBorderSize < 0) {\n throw new ValidationError(`Invalid borderSize: ${borderSize}`);\n }\n\n if (normalizedBorderSize > maxBorderSize) {\n throw new ValidationError(\n `Invalid borderSize: ${borderSize}. Maximum allowed for size ${normalizedSize} is ${maxBorderSize}`,\n );\n }\n\n return normalizedBorderSize;\n}\n\nexport function validateColorString(color: string, label = \"color\"): string {\n if (typeof color !== \"string\" || color.trim() === \"\") {\n throw new ValidationError(`Invalid ${label}: ${String(color)}`);\n }\n\n const normalized = color.trim();\n colorValidationContext.fillStyle = \"#010203\";\n colorValidationContext.fillStyle = normalized;\n const firstPass = String(colorValidationContext.fillStyle);\n colorValidationContext.fillStyle = \"#fefefe\";\n colorValidationContext.fillStyle = normalized;\n const secondPass = String(colorValidationContext.fillStyle);\n\n if (firstPass !== secondPass) {\n throw new ValidationError(`Invalid ${label}: ${color}`);\n }\n\n return normalized;\n}\n\nexport function validateBoardColors(colors?: BoardColors): void {\n if (!colors) {\n return;\n }\n\n if (colors.lightSquare !== undefined) {\n validateColorString(colors.lightSquare, \"lightSquare color\");\n }\n\n if (colors.darkSquare !== undefined) {\n validateColorString(colors.darkSquare, \"darkSquare color\");\n }\n\n if (colors.highlight !== undefined) {\n validateColorString(colors.highlight, \"highlight color\");\n }\n}\n\nfunction isCoordinatesOptions(value: unknown): value is CoordinatesOptions {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function validateCoordinatesOption(\n coordinates?: boolean | CoordinatesOptions,\n): void {\n if (coordinates === undefined || typeof coordinates === \"boolean\") {\n return;\n }\n\n if (!isCoordinatesOptions(coordinates)) {\n throw new ValidationError(\"coordinates must be a boolean or an options object\");\n }\n\n if (\n coordinates.enabled !== undefined &&\n typeof coordinates.enabled !== \"boolean\"\n ) {\n throw new ValidationError(\"coordinates.enabled must be a boolean\");\n }\n\n if (coordinates.color !== undefined) {\n validateColorString(coordinates.color, \"coordinates.color\");\n }\n}\n","import type { Square } from \"../types/types\";\nimport { validateSquare } from \"./validators\";\n\nexport function normalizeHighlights(input: string[]): Square[] {\n return [...new Set(input.map(validateSquare))].sort();\n}\n","import { createCanvas } from \"canvas\";\nimport { SQUARES } from \"../core/board\";\nimport { createBoardGeometry } from \"../core/geometry\";\nimport { RenderError } from \"../types/errors\";\nimport type { ThemeAssetSource } from \"../types/types\";\nimport { createRasterCacheKey, RasterAssetCache } from \"./asset-cache\";\nimport type { RenderRequest, Renderer } from \"./renderer\";\nimport { rasterizeThemeAsset } from \"./rasterizer\";\n\nconst pieceRasterCache = new RasterAssetCache<Awaited<ReturnType<typeof rasterizeThemeAsset>>>();\nconst MIN_COORDINATE_FONT_SIZE = 8;\nconst MAX_FILE_LABEL_WIDTH_RATIO = 0.75;\nconst MAX_RANK_LABEL_WIDTH_RATIO = 0.7;\nconst MAX_LABEL_HEIGHT_RATIO = 0.7;\n\nfunction isDarkSquare(square: string): boolean {\n const fileIndex = square.charCodeAt(0) - 97;\n const rankNumber = Number(square[1]);\n return (fileIndex + rankNumber) % 2 === 1;\n}\n\nasync function getPieceRaster(\n themeName: string,\n pieceKey: string,\n asset: ThemeAssetSource,\n squareSize: number,\n) {\n const cacheKey = createRasterCacheKey(themeName, pieceKey, squareSize, \"png-canvas\");\n const cached = pieceRasterCache.get(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const raster = await rasterizeThemeAsset(asset, squareSize);\n pieceRasterCache.set(cacheKey, raster);\n return raster;\n}\n\nfunction drawCoordinates(\n context: ReturnType<typeof createCanvas>[\"getContext\"],\n request: RenderRequest,\n geometry: ReturnType<typeof createBoardGeometry>,\n) {\n if (!request.coordinates.enabled || geometry.borderSize === 0) {\n return;\n }\n\n const maxFontSize = Math.floor(\n Math.min(geometry.squareSize * 0.6, geometry.borderSize * 0.65),\n );\n let fontSize: number | null = null;\n\n for (let candidate = maxFontSize; candidate >= MIN_COORDINATE_FONT_SIZE; candidate -= 1) {\n context.font = `${candidate}px sans-serif`;\n\n const filesFit = geometry.fileLabels.every((label) => {\n const metrics = context.measureText(label.text);\n const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\n\n return (\n metrics.width <= geometry.squareSize * MAX_FILE_LABEL_WIDTH_RATIO &&\n textHeight <= geometry.borderSize * MAX_LABEL_HEIGHT_RATIO\n );\n });\n const ranksFit = geometry.rankLabels.every((label) => {\n const metrics = context.measureText(label.text);\n const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\n\n return (\n metrics.width <= geometry.borderSize * MAX_RANK_LABEL_WIDTH_RATIO &&\n textHeight <= geometry.squareSize * MAX_LABEL_HEIGHT_RATIO\n );\n });\n\n if (filesFit && ranksFit) {\n fontSize = candidate;\n break;\n }\n }\n\n if (fontSize === null) {\n return;\n }\n\n context.fillStyle = request.coordinates.color;\n context.font = `${fontSize}px sans-serif`;\n context.textAlign = \"center\";\n context.textBaseline = \"middle\";\n\n for (const label of geometry.fileLabels) {\n context.fillText(label.text, label.x, label.y);\n }\n\n for (const label of geometry.rankLabels) {\n context.fillText(label.text, label.x, label.y);\n }\n}\n\nexport class CanvasPngRenderer implements Renderer<Buffer> {\n async render(request: RenderRequest): Promise<Buffer> {\n try {\n const geometry = createBoardGeometry({\n size: request.size,\n padding: request.padding,\n borderSize: request.borderSize,\n flipped: request.flipped,\n });\n\n const canvas = createCanvas(geometry.imageWidth, geometry.imageHeight);\n const context = canvas.getContext(\"2d\");\n\n context.fillStyle = request.colors.lightSquare;\n context.fillRect(0, 0, geometry.imageWidth, geometry.imageHeight);\n\n for (const square of SQUARES) {\n const squareGeometry = geometry.squares[square];\n context.fillStyle = isDarkSquare(square)\n ? request.colors.darkSquare\n : request.colors.lightSquare;\n context.fillRect(\n squareGeometry.x,\n squareGeometry.y,\n squareGeometry.size,\n squareGeometry.size,\n );\n\n if (request.highlights.includes(square)) {\n context.fillStyle = request.colors.highlight;\n context.fillRect(\n squareGeometry.x,\n squareGeometry.y,\n squareGeometry.size,\n squareGeometry.size,\n );\n }\n\n const pieceKey = request.board.squares[square];\n if (!pieceKey) {\n continue;\n }\n\n const raster = await getPieceRaster(\n request.theme.name,\n pieceKey,\n request.theme.pieces[pieceKey],\n Math.round(geometry.squareSize),\n );\n context.drawImage(\n raster,\n squareGeometry.x,\n squareGeometry.y,\n squareGeometry.size,\n squareGeometry.size,\n );\n }\n\n drawCoordinates(context, request, geometry);\n\n return canvas.toBuffer(\"image/png\");\n } catch (error) {\n if (error instanceof RenderError) {\n throw error;\n }\n\n throw new RenderError(\"Failed to render chess board\", { cause: error });\n }\n }\n}\n","import type { Padding, Square } from \"../types/types\";\nimport { FILES, RANKS, SQUARES } from \"./board\";\n\nexport interface SquareGeometry {\n x: number;\n y: number;\n size: number;\n}\n\nexport interface CoordinateLabelGeometry {\n text: string;\n x: number;\n y: number;\n}\n\nexport interface BoardGeometry {\n imageWidth: number;\n imageHeight: number;\n squareSize: number;\n borderSize: number;\n boardOuterX: number;\n boardOuterY: number;\n boardOuterSize: number;\n boardX: number;\n boardY: number;\n boardSize: number;\n fileLabels: CoordinateLabelGeometry[];\n rankLabels: CoordinateLabelGeometry[];\n squares: Record<Square, SquareGeometry>;\n}\n\ninterface BoardGeometryOptions {\n size: number;\n padding: Padding;\n borderSize: number;\n flipped: boolean;\n}\n\nexport function createBoardGeometry({\n size,\n padding,\n borderSize,\n flipped,\n}: BoardGeometryOptions): BoardGeometry {\n const [top, right, bottom, left] = padding;\n const boardOuterSize = size;\n const boardOuterX = left;\n const boardOuterY = top;\n const boardX = left + borderSize;\n const boardY = top + borderSize;\n const boardSize = size - borderSize * 2;\n const squareSize = boardSize / 8;\n\n const squares = Object.fromEntries(\n SQUARES.map((square, index) => {\n const fileIndex = index % 8;\n const rankIndex = Math.floor(index / 8);\n\n const x = boardX + (flipped ? 7 - fileIndex : fileIndex) * squareSize;\n const y = boardY + (flipped ? 7 - rankIndex : rankIndex) * squareSize;\n\n return [square, { x, y, size: squareSize }];\n }),\n ) as Record<Square, SquareGeometry>;\n\n const displayedFiles = flipped ? [...FILES].reverse() : [...FILES];\n const displayedRanks = flipped ? [...RANKS].reverse() : [...RANKS];\n const fileLabels = borderSize\n ? displayedFiles.map((file, fileIndex) => ({\n text: file,\n x: boardX + fileIndex * squareSize + squareSize / 2,\n y: boardOuterY + boardOuterSize - borderSize / 2,\n }))\n : [];\n const rankLabels = borderSize\n ? displayedRanks.map((rank, rankIndex) => ({\n text: rank,\n x: boardOuterX + borderSize / 2,\n y: boardY + rankIndex * squareSize + squareSize / 2,\n }))\n : [];\n\n return {\n imageWidth: left + size + right,\n imageHeight: top + size + bottom,\n squareSize,\n borderSize,\n boardOuterX,\n boardOuterY,\n boardOuterSize,\n boardX,\n boardY,\n boardSize,\n fileLabels,\n rankLabels,\n squares,\n };\n}\n","export function createRasterCacheKey(\n themeName: string,\n pieceKey: string,\n squareSize: number,\n backend: string,\n): string {\n return `${themeName}:${pieceKey}:${squareSize}:${backend}`;\n}\n\nexport class RasterAssetCache<T> {\n private readonly cache = new Map<string, T>();\n\n get(key: string): T | undefined {\n return this.cache.get(key);\n }\n\n set(key: string, value: T): void {\n this.cache.set(key, value);\n }\n}\n\nexport class SourceAssetCache<T> {\n private readonly cache = new Map<string, T>();\n\n get(key: string): T | undefined {\n return this.cache.get(key);\n }\n\n set(key: string, value: T): void {\n this.cache.set(key, value);\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { createCanvas, loadImage } from \"canvas\";\nimport { Resvg } from \"@resvg/resvg-js\";\nimport { RenderError } from \"../types/errors\";\nimport type { ThemeAssetSource } from \"../types/types\";\nimport { SourceAssetCache } from \"./asset-cache\";\n\nconst svgSourceCache = new SourceAssetCache<string>();\nconst imageBufferCache = new SourceAssetCache<Buffer>();\n\nasync function readSvgSource(filePath: string): Promise<string> {\n const cached = svgSourceCache.get(filePath);\n\n if (cached) {\n return cached;\n }\n\n try {\n const source = await readFile(filePath, \"utf8\");\n svgSourceCache.set(filePath, source);\n return source;\n } catch (error) {\n throw new RenderError(`Failed to read SVG asset: ${filePath}`, { cause: error });\n }\n}\n\nasync function readBinaryAsset(filePath: string): Promise<Buffer> {\n const cached = imageBufferCache.get(filePath);\n\n if (cached) {\n return cached;\n }\n\n try {\n const source = await readFile(filePath);\n imageBufferCache.set(filePath, source);\n return source;\n } catch (error) {\n throw new RenderError(`Failed to read image asset: ${filePath}`, { cause: error });\n }\n}\n\nasync function rasterizeSvgAsset(filePath: string, squareSize: number) {\n try {\n const svgSource = await readSvgSource(filePath);\n const resvg = new Resvg(svgSource, {\n fitTo: {\n mode: \"width\",\n value: squareSize,\n },\n });\n const pngBuffer = resvg.render().asPng();\n const image = await loadImage(pngBuffer);\n const canvas = createCanvas(squareSize, squareSize);\n const context = canvas.getContext(\"2d\");\n context.drawImage(image, 0, 0, squareSize, squareSize);\n return canvas;\n } catch (error) {\n throw new RenderError(`Failed to rasterize SVG asset: ${filePath}`, { cause: error });\n }\n}\n\nasync function rasterizePngAsset(filePath: string, squareSize: number) {\n try {\n const pngSource = await readBinaryAsset(filePath);\n const image = await loadImage(pngSource);\n const canvas = createCanvas(squareSize, squareSize);\n const context = canvas.getContext(\"2d\");\n context.drawImage(image, 0, 0, squareSize, squareSize);\n return canvas;\n } catch (error) {\n throw new RenderError(`Failed to rasterize PNG asset: ${filePath}`, { cause: error });\n }\n}\n\nexport async function rasterizeThemeAsset(asset: ThemeAssetSource, squareSize: number) {\n if (asset.kind === \"svg\") {\n return rasterizeSvgAsset(asset.source, squareSize);\n }\n\n return rasterizePngAsset(asset.source, squareSize);\n}\n","import { writeFile } from \"node:fs/promises\";\nimport { IOError } from \"../types/errors\";\n\nexport async function writeBufferToFile(filePath: string, buffer: Buffer): Promise<void> {\n try {\n await writeFile(filePath, buffer);\n } catch (error) {\n throw new IOError(`Failed to write file: ${filePath}`, { cause: error });\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { PieceKey, PieceStyle, ThemeDefinition } from \"../types/types\";\nimport { registerTheme } from \"./registry\";\n\nexport const builtInThemeNames = [\n \"merida\",\n \"alpha\",\n \"cburnett\",\n \"cheq\",\n \"leipzig\",\n] as const satisfies readonly PieceStyle[];\n\nconst PIECE_KEYS: PieceKey[] = [\n \"wK\",\n \"wQ\",\n \"wR\",\n \"wB\",\n \"wN\",\n \"wP\",\n \"bK\",\n \"bQ\",\n \"bR\",\n \"bB\",\n \"bN\",\n \"bP\",\n];\n\nlet initialized = false;\n\nfunction assetPath(themeName: PieceStyle, pieceKey: PieceKey): string {\n const candidates = [\n resolve(__dirname, \"../../assets/themes\", themeName, `${pieceKey}.png`),\n resolve(__dirname, \"../assets/themes\", themeName, `${pieceKey}.png`),\n resolve(process.cwd(), \"assets/themes\", themeName, `${pieceKey}.png`),\n ];\n\n const match = candidates.find((candidate) => existsSync(candidate));\n return match ?? candidates[0];\n}\n\nfunction createBuiltInTheme(themeName: PieceStyle): ThemeDefinition {\n return {\n name: themeName,\n displayName: themeName[0].toUpperCase() + themeName.slice(1),\n license: \"Derived from upstream chess-image-generator resource pack; original pack license not fully verified\",\n attribution:\n \"Derived from andyruwruw/chess-image-generator bundled resources; upstream README cites Marcel van Kervinck as source\",\n pieces: Object.fromEntries(\n PIECE_KEYS.map((pieceKey) => [\n pieceKey,\n {\n kind: \"png\",\n source: assetPath(themeName, pieceKey),\n },\n ]),\n ) as ThemeDefinition[\"pieces\"],\n };\n}\n\nexport function initializeBuiltInThemes(): void {\n if (initialized) {\n return;\n }\n\n for (const themeName of builtInThemeNames) {\n registerTheme(createBuiltInTheme(themeName));\n }\n\n initialized = true;\n}\n\nexport function resetBuiltInThemesForTesting(): void {\n initialized = false;\n}\n","import { validateThemeName } from \"../core/validators\";\nimport { ThemeError, ValidationError } from \"../types/errors\";\nimport type { PieceKey, ThemeDefinition } from \"../types/types\";\n\nconst REQUIRED_PIECES: PieceKey[] = [\n \"wK\",\n \"wQ\",\n \"wR\",\n \"wB\",\n \"wN\",\n \"wP\",\n \"bK\",\n \"bQ\",\n \"bR\",\n \"bB\",\n \"bN\",\n \"bP\",\n];\n\nexport function validateThemeDefinition(theme: ThemeDefinition): ThemeDefinition {\n const normalizedName = validateThemeName(theme.name);\n\n if (!theme.displayName.trim()) {\n throw new ValidationError(\"Theme displayName is required\");\n }\n\n if (!theme.license.trim()) {\n throw new ValidationError(\"Theme license is required\");\n }\n\n if (!theme.attribution.trim()) {\n throw new ValidationError(\"Theme attribution is required\");\n }\n\n for (const pieceKey of REQUIRED_PIECES) {\n const asset = theme.pieces[pieceKey];\n\n if (!asset || (asset.kind !== \"svg\" && asset.kind !== \"png\") || !asset.source.trim()) {\n throw new ThemeError(`Theme \"${normalizedName}\" is missing asset ${pieceKey}`);\n }\n }\n\n return {\n ...theme,\n name: normalizedName,\n };\n}\n","import type { ThemeDefinition } from \"../types/types\";\nimport { ThemeError } from \"../types/errors\";\nimport { validateThemeDefinition } from \"./validation\";\n\nconst registry = new Map<string, ThemeDefinition>();\n\nexport function registerTheme(theme: ThemeDefinition): ThemeDefinition {\n const validatedTheme = validateThemeDefinition(theme);\n\n if (registry.has(validatedTheme.name)) {\n throw new ThemeError(`Theme \"${validatedTheme.name}\" is already registered`);\n }\n\n registry.set(validatedTheme.name, validatedTheme);\n return validatedTheme;\n}\n\nexport function getTheme(name: string): ThemeDefinition | undefined {\n return registry.get(name.trim().toLowerCase());\n}\n\nexport function clearThemeRegistryForTesting(): void {\n registry.clear();\n}\n","import type { PieceStyle, ThemeDefinition } from \"../types/types\";\nimport { ThemeError, ValidationError } from \"../types/errors\";\nimport { initializeBuiltInThemes } from \"./builtins\";\nimport { getTheme } from \"./registry\";\nimport { validateThemeDefinition } from \"./validation\";\n\ninterface ResolveThemeOptions {\n theme?: string | ThemeDefinition;\n style?: PieceStyle;\n}\n\nexport function resolveTheme({ theme, style }: ResolveThemeOptions): ThemeDefinition {\n initializeBuiltInThemes();\n\n if (typeof theme === \"object\" && theme !== null) {\n try {\n return validateThemeDefinition(theme);\n } catch (error) {\n if (error instanceof ThemeError) {\n throw error;\n }\n\n if (error instanceof ValidationError) {\n throw new ThemeError(error.message, { cause: error });\n }\n\n throw error;\n }\n }\n\n const requestedName = typeof theme === \"string\" ? theme : style ?? \"merida\";\n const resolvedTheme = getTheme(requestedName);\n\n if (!resolvedTheme) {\n throw new ThemeError(`Unknown theme: ${requestedName}`);\n }\n\n return resolvedTheme;\n}\n","import type {\n BoardColors,\n CoordinatesOptions,\n Padding,\n RenderOptions,\n ResolvedColors,\n ResolvedCoordinates,\n ResolvedRenderOptions,\n Square,\n ThemeDefinition,\n} from \"../types/types\";\nimport { normalizeHighlights } from \"../core/highlights\";\nimport {\n normalizePadding,\n validateBoardColors,\n validateBorderSize,\n validateCoordinatesOption,\n validateSize,\n} from \"../core/validators\";\nimport { resolveTheme } from \"../themes/resolver\";\n\nexport const DEFAULT_SIZE = 480;\nexport const DEFAULT_PADDING: Padding = [0, 0, 0, 0];\nexport const DEFAULT_BORDER_SIZE = 0;\nexport const DEFAULT_COLORS: ResolvedColors = {\n lightSquare: \"#f0d9b5\",\n darkSquare: \"#b58863\",\n highlight: \"rgba(255, 206, 0, 0.45)\",\n};\nexport const DEFAULT_COORDINATES: ResolvedCoordinates = {\n enabled: false,\n color: \"#333\",\n};\n\nexport function normalizeColors(colors?: BoardColors): ResolvedColors {\n return {\n lightSquare: colors?.lightSquare ?? DEFAULT_COLORS.lightSquare,\n darkSquare: colors?.darkSquare ?? DEFAULT_COLORS.darkSquare,\n highlight: colors?.highlight ?? DEFAULT_COLORS.highlight,\n };\n}\n\nexport function normalizeCoordinates(\n coordinates?: boolean | CoordinatesOptions,\n): ResolvedCoordinates {\n if (coordinates === undefined || coordinates === false) {\n return { ...DEFAULT_COORDINATES };\n }\n\n if (coordinates === true) {\n return {\n enabled: true,\n color: DEFAULT_COORDINATES.color,\n };\n }\n\n return {\n enabled: coordinates.enabled ?? true,\n color: coordinates.color ?? DEFAULT_COORDINATES.color,\n };\n}\n\nexport function normalizeRenderInputs(\n options: RenderOptions & { highlightSquares?: Square[] },\n): ResolvedRenderOptions {\n const size = validateSize(options.size ?? DEFAULT_SIZE);\n const borderSize = validateBorderSize(\n options.borderSize ?? DEFAULT_BORDER_SIZE,\n size,\n );\n validateBoardColors(options.colors);\n validateCoordinatesOption(options.coordinates);\n\n return {\n size,\n padding: normalizePadding(options.padding ?? DEFAULT_PADDING),\n borderSize,\n flipped: options.flipped ?? false,\n theme: resolveTheme({\n theme: options.theme,\n style: options.style,\n }),\n highlightSquares: normalizeHighlights(options.highlightSquares ?? []),\n colors: normalizeColors(options.colors),\n coordinates: normalizeCoordinates(options.coordinates),\n };\n}\n","import { parseBoardArray, parseFEN, parsePGN } from \"../core/parsers\";\nimport { normalizeHighlights } from \"../core/highlights\";\nimport { ValidationError } from \"../types/errors\";\nimport type {\n BoardArray,\n ChessImageGeneratorOptions,\n RenderOptions,\n} from \"../types/types\";\nimport { CanvasPngRenderer } from \"../render/canvas-renderer\";\nimport { writeBufferToFile } from \"../utils/io\";\nimport { normalizeRenderInputs } from \"../utils/normalization\";\nimport type { BoardPosition } from \"../core/board\";\n\nexport class ChessImageGenerator {\n private position: BoardPosition | null = null;\n\n private readonly defaults: RenderOptions;\n\n private highlights: string[] = [];\n\n constructor(options: ChessImageGeneratorOptions = {}) {\n this.defaults = { ...options };\n normalizeRenderInputs({\n ...this.defaults,\n highlightSquares: [],\n });\n }\n\n async loadFEN(fen: string): Promise<void> {\n this.position = parseFEN(fen);\n this.clearHighlights();\n }\n\n async loadPGN(pgn: string): Promise<void> {\n this.position = parsePGN(pgn);\n this.clearHighlights();\n }\n\n async loadBoard(board: BoardArray): Promise<void> {\n this.position = parseBoardArray(board);\n this.clearHighlights();\n }\n\n setHighlights(squares: string[]): void {\n this.highlights = normalizeHighlights(squares);\n }\n\n clearHighlights(): void {\n this.highlights = [];\n }\n\n async toBuffer(): Promise<Buffer> {\n if (!this.position) {\n throw new ValidationError(\"No board position loaded\");\n }\n\n const renderer = new CanvasPngRenderer();\n const normalized = normalizeRenderInputs({\n ...this.defaults,\n highlightSquares: this.highlights,\n });\n\n return renderer.render({\n board: this.position,\n theme: normalized.theme,\n highlights: normalized.highlightSquares,\n size: normalized.size,\n padding: normalized.padding,\n borderSize: normalized.borderSize,\n flipped: normalized.flipped,\n colors: normalized.colors,\n coordinates: normalized.coordinates,\n });\n }\n\n async toFile(filePath: string): Promise<void> {\n const buffer = await this.toBuffer();\n await writeBufferToFile(filePath, buffer);\n }\n}\n","import { parseBoardArray, parseFEN, parsePGN } from \"../core/parsers\";\nimport { ValidationError } from \"../types/errors\";\nimport type { RenderChessOptions } from \"../types/types\";\nimport { CanvasPngRenderer } from \"../render/canvas-renderer\";\nimport { normalizeRenderInputs } from \"../utils/normalization\";\n\nfunction parseInputPosition(options: RenderChessOptions) {\n if (typeof options.fen === \"string\") {\n return parseFEN(options.fen);\n }\n\n if (typeof options.pgn === \"string\") {\n return parsePGN(options.pgn);\n }\n\n if (Array.isArray(options.board)) {\n return parseBoardArray(options.board);\n }\n\n throw new ValidationError(\"Exactly one of fen, pgn, or board must be provided\");\n}\n\nexport async function renderChess(options: RenderChessOptions): Promise<Buffer> {\n const provided = [\n typeof options.fen === \"string\" ? options.fen : undefined,\n typeof options.pgn === \"string\" ? options.pgn : undefined,\n Array.isArray(options.board) ? options.board : undefined,\n ].filter((value) => value !== undefined);\n\n if (provided.length !== 1) {\n throw new ValidationError(\"Exactly one of fen, pgn, or board must be provided\");\n }\n\n const position = parseInputPosition(options);\n const renderer = new CanvasPngRenderer();\n const normalized = normalizeRenderInputs(options);\n\n return renderer.render({\n board: position,\n theme: normalized.theme,\n highlights: normalized.highlightSquares,\n size: normalized.size,\n padding: normalized.padding,\n borderSize: normalized.borderSize,\n flipped: normalized.flipped,\n colors: normalized.colors,\n coordinates: normalized.coordinates,\n });\n}\n"],"mappings":"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","names":["import_canvas","import_canvas","import_promises"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types/errors.ts","../src/core/parsers.ts","../src/core/board.ts","../src/core/validators.ts","../src/core/highlights.ts","../src/render/canvas-renderer.ts","../src/core/geometry.ts","../src/render/asset-cache.ts","../src/render/rasterizer.ts","../src/utils/io.ts","../src/themes/builtins.ts","../src/themes/validation.ts","../src/themes/registry.ts","../src/themes/resolver.ts","../src/utils/normalization.ts","../src/api/class-api.ts","../src/api/functional-api.ts"],"sourcesContent":["export * from \"./types/errors\";\nexport * from \"./types/types\";\nexport * from \"./api/class-api\";\nexport * from \"./api/functional-api\";\nexport * from \"./api/theme-api\";\n","export class ValidationError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"ValidationError\";\n }\n}\n\nexport class ParseError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"ParseError\";\n }\n}\n\nexport class ThemeError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"ThemeError\";\n }\n}\n\nexport class RenderError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"RenderError\";\n }\n}\n\nexport class IOError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"IOError\";\n }\n}\n","import { Chess } from \"chess.js\";\nimport type { BoardArray, BoardCell, PieceKey } from \"../types/types\";\nimport { ParseError, ValidationError } from \"../types/errors\";\nimport { createEmptyBoardPosition, FILES } from \"./board\";\nimport { validateBoardArray } from \"./validators\";\n\nconst PIECE_SYMBOL_TO_KEY: Record<string, PieceKey> = {\n K: \"wK\",\n Q: \"wQ\",\n R: \"wR\",\n B: \"wB\",\n N: \"wN\",\n P: \"wP\",\n k: \"bK\",\n q: \"bQ\",\n r: \"bR\",\n b: \"bB\",\n n: \"bN\",\n p: \"bP\",\n};\n\nfunction chessBoardToBoardArray(board: ReturnType<Chess[\"board\"]>): BoardArray {\n return board.map((rank) =>\n rank.map((piece): BoardCell => {\n if (!piece) {\n return null;\n }\n\n return piece.color === \"w\" ? piece.type.toUpperCase() : piece.type;\n }),\n );\n}\n\nexport function parseFEN(fen: string) {\n const chess = new Chess();\n\n try {\n chess.load(fen);\n } catch (error) {\n throw new ParseError(\"Invalid FEN\", { cause: error });\n }\n\n return parseBoardArray(chessBoardToBoardArray(chess.board()));\n}\n\nexport function parsePGN(pgn: string) {\n const chess = new Chess();\n\n try {\n chess.loadPgn(pgn);\n } catch (error) {\n throw new ParseError(\"Invalid PGN\", { cause: error });\n }\n\n return parseBoardArray(chessBoardToBoardArray(chess.board()));\n}\n\nexport function parseBoardArray(board: BoardArray) {\n const validatedBoard = validateBoardArray(board);\n const position = createEmptyBoardPosition();\n\n validatedBoard.forEach((rank, rankIndex) => {\n rank.forEach((cell, fileIndex) => {\n if (cell === null) {\n return;\n }\n\n const pieceKey = PIECE_SYMBOL_TO_KEY[cell];\n\n if (!pieceKey) {\n throw new ValidationError(`Invalid board piece: ${cell}`);\n }\n\n const square = `${FILES[fileIndex]}${8 - rankIndex}` as keyof typeof position.squares;\n position.squares[square] = pieceKey;\n });\n });\n\n return position;\n}\n","import type { PieceKey, Square } from \"../types/types\";\n\nexport const FILES = [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"] as const;\nexport const RANKS = [\"8\", \"7\", \"6\", \"5\", \"4\", \"3\", \"2\", \"1\"] as const;\n\nexport const SQUARES: Square[] = RANKS.flatMap((rank) =>\n FILES.map((file) => `${file}${rank}`),\n);\n\nexport interface BoardPosition {\n squares: Record<Square, PieceKey | null>;\n}\n\nexport function createEmptyBoardPosition(): BoardPosition {\n return {\n squares: Object.fromEntries(\n SQUARES.map((square) => [square, null]),\n ) as Record<Square, PieceKey | null>,\n };\n}\n","import { createCanvas } from \"canvas\";\nimport type {\n BoardArray,\n BoardCell,\n BoardColors,\n CoordinatesInput,\n CoordinatesOptions,\n CoordinatesPosition,\n Padding,\n Square,\n} from \"../types/types\";\nimport { ValidationError } from \"../types/errors\";\n\nconst SQUARE_PATTERN = /^[a-h][1-8]$/;\nconst PIECE_PATTERN = /^[prnbqkPRNBQK]$/;\nconst BUILT_IN_THEME_PATTERN = /^(merida|alpha|cburnett|cheq|leipzig)$/;\nconst colorValidationContext = createCanvas(1, 1).getContext(\"2d\");\n\nexport function validateSize(size: number): number {\n if (!Number.isFinite(size) || size <= 0) {\n throw new ValidationError(`Invalid board size: ${size}`);\n }\n\n return Math.round(size);\n}\n\nexport function normalizePadding(padding?: number[] | Padding): Padding {\n const candidate = padding ?? [0, 0, 0, 0];\n\n if (\n !Array.isArray(candidate) ||\n candidate.length !== 4 ||\n candidate.some((value) => !Number.isFinite(value) || value < 0)\n ) {\n throw new ValidationError(\"Padding must be a 4-item array of non-negative numbers\");\n }\n\n return [\n Math.round(candidate[0]),\n Math.round(candidate[1]),\n Math.round(candidate[2]),\n Math.round(candidate[3]),\n ];\n}\n\nexport function validateSquare(square: string): Square {\n const normalized = square.trim().toLowerCase();\n\n if (!SQUARE_PATTERN.test(normalized)) {\n throw new ValidationError(`Invalid square: ${square}`);\n }\n\n return normalized;\n}\n\nexport function validateBoardCell(cell: BoardCell): BoardCell {\n if (cell === null || cell === \"\" || cell === \" \") {\n return null;\n }\n\n if (typeof cell !== \"string\" || !PIECE_PATTERN.test(cell)) {\n throw new ValidationError(`Invalid board piece: ${String(cell)}`);\n }\n\n return cell;\n}\n\nexport function validateBoardArray(board: BoardArray): BoardArray {\n if (!Array.isArray(board) || board.length !== 8) {\n throw new ValidationError(\"Board array must have exactly 8 ranks\");\n }\n\n return board.map((rank, rankIndex) => {\n if (!Array.isArray(rank) || rank.length !== 8) {\n throw new ValidationError(`Board rank ${rankIndex} must contain exactly 8 files`);\n }\n\n return rank.map(validateBoardCell);\n });\n}\n\nexport function validateStyleName(style: string): string {\n const normalized = style.trim().toLowerCase();\n\n if (!BUILT_IN_THEME_PATTERN.test(normalized)) {\n throw new ValidationError(`Unknown built-in style: ${style}`);\n }\n\n return normalized;\n}\n\nexport function validateThemeName(name: string): string {\n const normalized = name.trim().toLowerCase();\n\n if (!/^[a-z0-9-]+$/.test(normalized)) {\n throw new ValidationError(`Invalid theme name: ${name}`);\n }\n\n return normalized;\n}\n\nexport function validateBorderSize(borderSize: number, size: number): number {\n const normalizedSize = validateSize(size);\n const normalizedBorderSize = Math.round(borderSize);\n const maxBorderSize = Math.floor(normalizedSize / 8);\n\n if (!Number.isFinite(borderSize) || normalizedBorderSize < 0) {\n throw new ValidationError(`Invalid borderSize: ${borderSize}`);\n }\n\n if (normalizedBorderSize > maxBorderSize) {\n throw new ValidationError(\n `Invalid borderSize: ${borderSize}. Maximum allowed for size ${normalizedSize} is ${maxBorderSize}`,\n );\n }\n\n return normalizedBorderSize;\n}\n\nexport function validateColorString(color: string, label = \"color\"): string {\n if (typeof color !== \"string\" || color.trim() === \"\") {\n throw new ValidationError(`Invalid ${label}: ${String(color)}`);\n }\n\n const normalized = color.trim();\n colorValidationContext.fillStyle = \"#010203\";\n colorValidationContext.fillStyle = normalized;\n const firstPass = String(colorValidationContext.fillStyle);\n colorValidationContext.fillStyle = \"#fefefe\";\n colorValidationContext.fillStyle = normalized;\n const secondPass = String(colorValidationContext.fillStyle);\n\n if (firstPass !== secondPass) {\n throw new ValidationError(`Invalid ${label}: ${color}`);\n }\n\n return normalized;\n}\n\nexport function validateBoardColors(colors?: BoardColors): void {\n if (!colors) {\n return;\n }\n\n if (colors.lightSquare !== undefined) {\n validateColorString(colors.lightSquare, \"lightSquare color\");\n }\n\n if (colors.darkSquare !== undefined) {\n validateColorString(colors.darkSquare, \"darkSquare color\");\n }\n\n if (colors.highlight !== undefined) {\n validateColorString(colors.highlight, \"highlight color\");\n }\n}\n\nfunction isCoordinatesOptions(value: unknown): value is CoordinatesOptions {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isCoordinatesPosition(value: unknown): value is CoordinatesPosition {\n return value === \"border\" || value === \"inside\";\n}\n\nexport function validateCoordinatesOption(\n coordinates: CoordinatesInput | undefined,\n borderSize: number,\n): void {\n if (coordinates === undefined || typeof coordinates === \"boolean\") {\n return;\n }\n\n if (isCoordinatesPosition(coordinates)) {\n if (coordinates === \"border\" && borderSize === 0) {\n throw new ValidationError(\n \"coordinates position 'border' requires borderSize > 0\",\n );\n }\n\n return;\n }\n\n if (!isCoordinatesOptions(coordinates)) {\n throw new ValidationError(\n \"coordinates must be false, true, 'border', 'inside', or an options object\",\n );\n }\n\n if (\n coordinates.enabled !== undefined &&\n typeof coordinates.enabled !== \"boolean\"\n ) {\n throw new ValidationError(\"coordinates.enabled must be a boolean\");\n }\n\n if (\n coordinates.position !== undefined &&\n !isCoordinatesPosition(coordinates.position)\n ) {\n throw new ValidationError(\"coordinates.position must be 'border' or 'inside'\");\n }\n\n if (\n coordinates.enabled !== false &&\n coordinates.position === \"border\" &&\n borderSize === 0\n ) {\n throw new ValidationError(\n \"coordinates position 'border' requires borderSize > 0\",\n );\n }\n\n if (coordinates.color !== undefined) {\n validateColorString(coordinates.color, \"coordinates.color\");\n }\n}\n","import type { Square } from \"../types/types\";\nimport { validateSquare } from \"./validators\";\n\nexport function normalizeHighlights(input: string[]): Square[] {\n return [...new Set(input.map(validateSquare))].sort();\n}\n","import { createCanvas } from \"canvas\";\nimport { SQUARES } from \"../core/board\";\nimport { createBoardGeometry } from \"../core/geometry\";\nimport { RenderError } from \"../types/errors\";\nimport type { ThemeAssetSource } from \"../types/types\";\nimport { createRasterCacheKey, RasterAssetCache } from \"./asset-cache\";\nimport type { RenderRequest, Renderer } from \"./renderer\";\nimport { rasterizeThemeAsset } from \"./rasterizer\";\n\nconst pieceRasterCache = new RasterAssetCache<Awaited<ReturnType<typeof rasterizeThemeAsset>>>();\nconst MIN_COORDINATE_FONT_SIZE = 8;\nconst MAX_FILE_LABEL_WIDTH_RATIO = 0.75;\nconst MAX_RANK_LABEL_WIDTH_RATIO = 0.7;\nconst MAX_LABEL_HEIGHT_RATIO = 0.7;\nconst INSIDE_COORDINATE_MAX_FONT_RATIO = 0.34;\nconst INSIDE_LIGHT_LABEL_COLOR = \"rgba(255,255,255,0.6)\";\nconst INSIDE_DARK_LABEL_COLOR = \"rgba(0,0,0,0.45)\";\n\nfunction isDarkSquare(square: string): boolean {\n const fileIndex = square.charCodeAt(0) - 97;\n const rankNumber = Number(square[1]);\n return (fileIndex + rankNumber) % 2 === 1;\n}\n\nasync function getPieceRaster(\n themeName: string,\n pieceKey: string,\n asset: ThemeAssetSource,\n squareSize: number,\n) {\n const cacheKey = createRasterCacheKey(themeName, pieceKey, squareSize, \"png-canvas\");\n const cached = pieceRasterCache.get(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const raster = await rasterizeThemeAsset(asset, squareSize);\n pieceRasterCache.set(cacheKey, raster);\n return raster;\n}\n\nfunction resolveInsideLabelColor(\n request: RenderRequest,\n square: string,\n) {\n if (request.coordinates.color) {\n return request.coordinates.color;\n }\n\n return isDarkSquare(square) ? INSIDE_LIGHT_LABEL_COLOR : INSIDE_DARK_LABEL_COLOR;\n}\n\nfunction resolveBorderCoordinateFontSize(\n context: ReturnType<typeof createCanvas>[\"getContext\"],\n geometry: ReturnType<typeof createBoardGeometry>,\n) {\n const maxFontSize = Math.floor(\n Math.min(geometry.squareSize * 0.6, geometry.borderSize * 0.65),\n );\n let fontSize: number | null = null;\n\n for (let candidate = maxFontSize; candidate >= MIN_COORDINATE_FONT_SIZE; candidate -= 1) {\n context.font = `${candidate}px sans-serif`;\n\n const filesFit = geometry.borderFileLabels.every((label) => {\n const metrics = context.measureText(label.text);\n const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\n\n return (\n metrics.width <= geometry.squareSize * MAX_FILE_LABEL_WIDTH_RATIO &&\n textHeight <= geometry.borderSize * MAX_LABEL_HEIGHT_RATIO\n );\n });\n const ranksFit = geometry.borderRankLabels.every((label) => {\n const metrics = context.measureText(label.text);\n const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\n\n return (\n metrics.width <= geometry.borderSize * MAX_RANK_LABEL_WIDTH_RATIO &&\n textHeight <= geometry.squareSize * MAX_LABEL_HEIGHT_RATIO\n );\n });\n\n if (filesFit && ranksFit) {\n fontSize = candidate;\n break;\n }\n }\n\n return fontSize;\n}\n\nfunction resolveInsideCoordinateFontSize(\n context: ReturnType<typeof createCanvas>[\"getContext\"],\n geometry: ReturnType<typeof createBoardGeometry>,\n) {\n const maxFontSize = Math.floor(\n geometry.squareSize * INSIDE_COORDINATE_MAX_FONT_RATIO,\n );\n let fontSize: number | null = null;\n\n for (let candidate = maxFontSize; candidate >= MIN_COORDINATE_FONT_SIZE; candidate -= 1) {\n context.font = `${candidate}px sans-serif`;\n\n const filesFit = geometry.insideFileLabels.every((label) => {\n const metrics = context.measureText(label.text);\n const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\n\n return (\n metrics.width <= geometry.insideLabelMaxWidth &&\n textHeight <= geometry.insideLabelMaxHeight\n );\n });\n const ranksFit = geometry.insideRankLabels.every((label) => {\n const metrics = context.measureText(label.text);\n const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\n\n return (\n metrics.width <= geometry.insideLabelMaxWidth &&\n textHeight <= geometry.insideLabelMaxHeight\n );\n });\n\n if (filesFit && ranksFit) {\n fontSize = candidate;\n break;\n }\n }\n\n return fontSize;\n}\n\nfunction drawBorderCoordinates(\n context: ReturnType<typeof createCanvas>[\"getContext\"],\n request: RenderRequest,\n geometry: ReturnType<typeof createBoardGeometry>,\n) {\n if (geometry.borderSize === 0) {\n return;\n }\n\n const fontSize = resolveBorderCoordinateFontSize(context, geometry);\n\n if (fontSize === null) {\n return;\n }\n\n context.fillStyle = request.coordinates.color ?? \"#333\";\n context.font = `${fontSize}px sans-serif`;\n context.textAlign = \"center\";\n context.textBaseline = \"middle\";\n\n for (const label of geometry.borderFileLabels) {\n context.fillText(label.text, label.x, label.y);\n }\n\n for (const label of geometry.borderRankLabels) {\n context.fillText(label.text, label.x, label.y);\n }\n}\n\nfunction drawInsideCoordinates(\n context: ReturnType<typeof createCanvas>[\"getContext\"],\n request: RenderRequest,\n geometry: ReturnType<typeof createBoardGeometry>,\n) {\n const fontSize = resolveInsideCoordinateFontSize(context, geometry);\n\n if (fontSize === null) {\n return;\n }\n\n context.font = `${fontSize}px sans-serif`;\n\n for (const label of geometry.insideFileLabels) {\n context.fillStyle = resolveInsideLabelColor(request, label.square);\n context.textAlign = label.textAlign;\n context.textBaseline = label.textBaseline;\n context.fillText(label.text, label.x, label.y);\n }\n\n for (const label of geometry.insideRankLabels) {\n context.fillStyle = resolveInsideLabelColor(request, label.square);\n context.textAlign = label.textAlign;\n context.textBaseline = label.textBaseline;\n context.fillText(label.text, label.x, label.y);\n }\n}\n\nfunction drawCoordinates(\n context: ReturnType<typeof createCanvas>[\"getContext\"],\n request: RenderRequest,\n geometry: ReturnType<typeof createBoardGeometry>,\n) {\n if (!request.coordinates.enabled) {\n return;\n }\n\n if (request.coordinates.position === \"border\") {\n drawBorderCoordinates(context, request, geometry);\n return;\n }\n\n drawInsideCoordinates(context, request, geometry);\n}\n\nexport class CanvasPngRenderer implements Renderer<Buffer> {\n async render(request: RenderRequest): Promise<Buffer> {\n try {\n const geometry = createBoardGeometry({\n size: request.size,\n padding: request.padding,\n borderSize: request.borderSize,\n flipped: request.flipped,\n });\n\n const canvas = createCanvas(geometry.imageWidth, geometry.imageHeight);\n const context = canvas.getContext(\"2d\");\n\n context.fillStyle = request.colors.lightSquare;\n context.fillRect(0, 0, geometry.imageWidth, geometry.imageHeight);\n\n for (const square of SQUARES) {\n const squareGeometry = geometry.squares[square];\n context.fillStyle = isDarkSquare(square)\n ? request.colors.darkSquare\n : request.colors.lightSquare;\n context.fillRect(\n squareGeometry.x,\n squareGeometry.y,\n squareGeometry.size,\n squareGeometry.size,\n );\n\n if (request.highlights.includes(square)) {\n context.fillStyle = request.colors.highlight;\n context.fillRect(\n squareGeometry.x,\n squareGeometry.y,\n squareGeometry.size,\n squareGeometry.size,\n );\n }\n\n const pieceKey = request.board.squares[square];\n if (!pieceKey) {\n continue;\n }\n\n const raster = await getPieceRaster(\n request.theme.name,\n pieceKey,\n request.theme.pieces[pieceKey],\n Math.round(geometry.squareSize),\n );\n context.drawImage(\n raster,\n squareGeometry.x,\n squareGeometry.y,\n squareGeometry.size,\n squareGeometry.size,\n );\n }\n\n drawCoordinates(context, request, geometry);\n\n return canvas.toBuffer(\"image/png\");\n } catch (error) {\n if (error instanceof RenderError) {\n throw error;\n }\n\n throw new RenderError(\"Failed to render chess board\", { cause: error });\n }\n }\n}\n","import type { Padding, Square } from \"../types/types\";\nimport { FILES, RANKS, SQUARES } from \"./board\";\n\nexport interface SquareGeometry {\n x: number;\n y: number;\n size: number;\n}\n\nexport interface CoordinateLabelGeometry {\n text: string;\n x: number;\n y: number;\n square: Square;\n textAlign: \"left\" | \"center\" | \"right\";\n textBaseline: \"top\" | \"middle\" | \"bottom\";\n}\n\nexport interface BoardGeometry {\n imageWidth: number;\n imageHeight: number;\n squareSize: number;\n borderSize: number;\n boardOuterX: number;\n boardOuterY: number;\n boardOuterSize: number;\n boardX: number;\n boardY: number;\n boardSize: number;\n borderFileLabels: CoordinateLabelGeometry[];\n borderRankLabels: CoordinateLabelGeometry[];\n insideFileLabels: CoordinateLabelGeometry[];\n insideRankLabels: CoordinateLabelGeometry[];\n insideFileInsetX: number;\n insideFileInsetY: number;\n insideRankInsetX: number;\n insideRankInsetY: number;\n insideLabelMaxWidth: number;\n insideLabelMaxHeight: number;\n squares: Record<Square, SquareGeometry>;\n}\n\ninterface BoardGeometryOptions {\n size: number;\n padding: Padding;\n borderSize: number;\n flipped: boolean;\n}\n\nexport function createBoardGeometry({\n size,\n padding,\n borderSize,\n flipped,\n}: BoardGeometryOptions): BoardGeometry {\n const [top, right, bottom, left] = padding;\n const boardOuterSize = size;\n const boardOuterX = left;\n const boardOuterY = top;\n const boardX = left + borderSize;\n const boardY = top + borderSize;\n const boardSize = size - borderSize * 2;\n const squareSize = boardSize / 8;\n\n const squares = Object.fromEntries(\n SQUARES.map((square, index) => {\n const fileIndex = index % 8;\n const rankIndex = Math.floor(index / 8);\n\n const x = boardX + (flipped ? 7 - fileIndex : fileIndex) * squareSize;\n const y = boardY + (flipped ? 7 - rankIndex : rankIndex) * squareSize;\n\n return [square, { x, y, size: squareSize }];\n }),\n ) as Record<Square, SquareGeometry>;\n\n const displayedFiles = flipped ? [...FILES].reverse() : [...FILES];\n const displayedRanks = flipped ? [...RANKS].reverse() : [...RANKS];\n const bottomEdgeRank = flipped ? \"8\" : \"1\";\n const leftEdgeFile = flipped ? \"h\" : \"a\";\n const borderFileLabels = borderSize\n ? displayedFiles.map((file, fileIndex) => ({\n text: file,\n x: boardX + fileIndex * squareSize + squareSize / 2,\n y: boardOuterY + boardOuterSize - borderSize / 2,\n square: `${file}${bottomEdgeRank}` as Square,\n textAlign: \"center\" as const,\n textBaseline: \"middle\" as const,\n }))\n : [];\n const borderRankLabels = borderSize\n ? displayedRanks.map((rank, rankIndex) => ({\n text: rank,\n x: boardOuterX + borderSize / 2,\n y: boardY + rankIndex * squareSize + squareSize / 2,\n square: `${leftEdgeFile}${rank}` as Square,\n textAlign: \"center\" as const,\n textBaseline: \"middle\" as const,\n }))\n : [];\n const insideFileInsetX = squareSize * 0.14;\n const insideFileInsetY = squareSize * 0.1;\n const insideRankInsetX = squareSize * 0.14;\n const insideRankInsetY = squareSize * 0.1;\n const insideLabelMaxWidth = squareSize * 0.26;\n const insideLabelMaxHeight = squareSize * 0.24;\n const insideFileLabels = displayedFiles.map((file) => {\n const square = `${file}${bottomEdgeRank}` as Square;\n const squareGeometry = squares[square];\n\n return {\n text: file,\n x: squareGeometry.x + squareGeometry.size - insideFileInsetX,\n y: squareGeometry.y + squareGeometry.size - insideFileInsetY,\n square,\n textAlign: \"right\" as const,\n textBaseline: \"bottom\" as const,\n };\n });\n const insideRankLabels = displayedRanks.map((rank) => {\n const square = `${leftEdgeFile}${rank}` as Square;\n const squareGeometry = squares[square];\n\n return {\n text: rank,\n x: squareGeometry.x + insideRankInsetX,\n y: squareGeometry.y + insideRankInsetY,\n square,\n textAlign: \"left\" as const,\n textBaseline: \"top\" as const,\n };\n });\n\n return {\n imageWidth: left + size + right,\n imageHeight: top + size + bottom,\n squareSize,\n borderSize,\n boardOuterX,\n boardOuterY,\n boardOuterSize,\n boardX,\n boardY,\n boardSize,\n borderFileLabels,\n borderRankLabels,\n insideFileLabels,\n insideRankLabels,\n insideFileInsetX,\n insideFileInsetY,\n insideRankInsetX,\n insideRankInsetY,\n insideLabelMaxWidth,\n insideLabelMaxHeight,\n squares,\n };\n}\n","export function createRasterCacheKey(\n themeName: string,\n pieceKey: string,\n squareSize: number,\n backend: string,\n): string {\n return `${themeName}:${pieceKey}:${squareSize}:${backend}`;\n}\n\nexport class RasterAssetCache<T> {\n private readonly cache = new Map<string, T>();\n\n get(key: string): T | undefined {\n return this.cache.get(key);\n }\n\n set(key: string, value: T): void {\n this.cache.set(key, value);\n }\n}\n\nexport class SourceAssetCache<T> {\n private readonly cache = new Map<string, T>();\n\n get(key: string): T | undefined {\n return this.cache.get(key);\n }\n\n set(key: string, value: T): void {\n this.cache.set(key, value);\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { createCanvas, loadImage } from \"canvas\";\nimport { Resvg } from \"@resvg/resvg-js\";\nimport { RenderError } from \"../types/errors\";\nimport type { ThemeAssetSource } from \"../types/types\";\nimport { SourceAssetCache } from \"./asset-cache\";\n\nconst svgSourceCache = new SourceAssetCache<string>();\nconst imageBufferCache = new SourceAssetCache<Buffer>();\n\nasync function readSvgSource(filePath: string): Promise<string> {\n const cached = svgSourceCache.get(filePath);\n\n if (cached) {\n return cached;\n }\n\n try {\n const source = await readFile(filePath, \"utf8\");\n svgSourceCache.set(filePath, source);\n return source;\n } catch (error) {\n throw new RenderError(`Failed to read SVG asset: ${filePath}`, { cause: error });\n }\n}\n\nasync function readBinaryAsset(filePath: string): Promise<Buffer> {\n const cached = imageBufferCache.get(filePath);\n\n if (cached) {\n return cached;\n }\n\n try {\n const source = await readFile(filePath);\n imageBufferCache.set(filePath, source);\n return source;\n } catch (error) {\n throw new RenderError(`Failed to read image asset: ${filePath}`, { cause: error });\n }\n}\n\nasync function rasterizeSvgAsset(filePath: string, squareSize: number) {\n try {\n const svgSource = await readSvgSource(filePath);\n const resvg = new Resvg(svgSource, {\n fitTo: {\n mode: \"width\",\n value: squareSize,\n },\n });\n const pngBuffer = resvg.render().asPng();\n const image = await loadImage(pngBuffer);\n const canvas = createCanvas(squareSize, squareSize);\n const context = canvas.getContext(\"2d\");\n context.drawImage(image, 0, 0, squareSize, squareSize);\n return canvas;\n } catch (error) {\n throw new RenderError(`Failed to rasterize SVG asset: ${filePath}`, { cause: error });\n }\n}\n\nasync function rasterizePngAsset(filePath: string, squareSize: number) {\n try {\n const pngSource = await readBinaryAsset(filePath);\n const image = await loadImage(pngSource);\n const canvas = createCanvas(squareSize, squareSize);\n const context = canvas.getContext(\"2d\");\n context.drawImage(image, 0, 0, squareSize, squareSize);\n return canvas;\n } catch (error) {\n throw new RenderError(`Failed to rasterize PNG asset: ${filePath}`, { cause: error });\n }\n}\n\nexport async function rasterizeThemeAsset(asset: ThemeAssetSource, squareSize: number) {\n if (asset.kind === \"svg\") {\n return rasterizeSvgAsset(asset.source, squareSize);\n }\n\n return rasterizePngAsset(asset.source, squareSize);\n}\n","import { writeFile } from \"node:fs/promises\";\nimport { IOError } from \"../types/errors\";\n\nexport async function writeBufferToFile(filePath: string, buffer: Buffer): Promise<void> {\n try {\n await writeFile(filePath, buffer);\n } catch (error) {\n throw new IOError(`Failed to write file: ${filePath}`, { cause: error });\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { PieceKey, PieceStyle, ThemeDefinition } from \"../types/types\";\nimport { registerTheme } from \"./registry\";\n\nexport const builtInThemeNames = [\n \"merida\",\n \"alpha\",\n \"cburnett\",\n \"cheq\",\n \"leipzig\",\n] as const satisfies readonly PieceStyle[];\n\nconst PIECE_KEYS: PieceKey[] = [\n \"wK\",\n \"wQ\",\n \"wR\",\n \"wB\",\n \"wN\",\n \"wP\",\n \"bK\",\n \"bQ\",\n \"bR\",\n \"bB\",\n \"bN\",\n \"bP\",\n];\n\nlet initialized = false;\n\nfunction assetPath(themeName: PieceStyle, pieceKey: PieceKey): string {\n const candidates = [\n resolve(__dirname, \"../../assets/themes\", themeName, `${pieceKey}.png`),\n resolve(__dirname, \"../assets/themes\", themeName, `${pieceKey}.png`),\n resolve(process.cwd(), \"assets/themes\", themeName, `${pieceKey}.png`),\n ];\n\n const match = candidates.find((candidate) => existsSync(candidate));\n return match ?? candidates[0];\n}\n\nfunction createBuiltInTheme(themeName: PieceStyle): ThemeDefinition {\n return {\n name: themeName,\n displayName: themeName[0].toUpperCase() + themeName.slice(1),\n license: \"Derived from upstream chess-image-generator resource pack; original pack license not fully verified\",\n attribution:\n \"Derived from andyruwruw/chess-image-generator bundled resources; upstream README cites Marcel van Kervinck as source\",\n pieces: Object.fromEntries(\n PIECE_KEYS.map((pieceKey) => [\n pieceKey,\n {\n kind: \"png\",\n source: assetPath(themeName, pieceKey),\n },\n ]),\n ) as ThemeDefinition[\"pieces\"],\n };\n}\n\nexport function initializeBuiltInThemes(): void {\n if (initialized) {\n return;\n }\n\n for (const themeName of builtInThemeNames) {\n registerTheme(createBuiltInTheme(themeName));\n }\n\n initialized = true;\n}\n\nexport function resetBuiltInThemesForTesting(): void {\n initialized = false;\n}\n","import { validateThemeName } from \"../core/validators\";\nimport { ThemeError, ValidationError } from \"../types/errors\";\nimport type { PieceKey, ThemeDefinition } from \"../types/types\";\n\nconst REQUIRED_PIECES: PieceKey[] = [\n \"wK\",\n \"wQ\",\n \"wR\",\n \"wB\",\n \"wN\",\n \"wP\",\n \"bK\",\n \"bQ\",\n \"bR\",\n \"bB\",\n \"bN\",\n \"bP\",\n];\n\nexport function validateThemeDefinition(theme: ThemeDefinition): ThemeDefinition {\n const normalizedName = validateThemeName(theme.name);\n\n if (!theme.displayName.trim()) {\n throw new ValidationError(\"Theme displayName is required\");\n }\n\n if (!theme.license.trim()) {\n throw new ValidationError(\"Theme license is required\");\n }\n\n if (!theme.attribution.trim()) {\n throw new ValidationError(\"Theme attribution is required\");\n }\n\n for (const pieceKey of REQUIRED_PIECES) {\n const asset = theme.pieces[pieceKey];\n\n if (!asset || (asset.kind !== \"svg\" && asset.kind !== \"png\") || !asset.source.trim()) {\n throw new ThemeError(`Theme \"${normalizedName}\" is missing asset ${pieceKey}`);\n }\n }\n\n return {\n ...theme,\n name: normalizedName,\n };\n}\n","import type { ThemeDefinition } from \"../types/types\";\nimport { ThemeError } from \"../types/errors\";\nimport { validateThemeDefinition } from \"./validation\";\n\nconst registry = new Map<string, ThemeDefinition>();\n\nexport function registerTheme(theme: ThemeDefinition): ThemeDefinition {\n const validatedTheme = validateThemeDefinition(theme);\n\n if (registry.has(validatedTheme.name)) {\n throw new ThemeError(`Theme \"${validatedTheme.name}\" is already registered`);\n }\n\n registry.set(validatedTheme.name, validatedTheme);\n return validatedTheme;\n}\n\nexport function getTheme(name: string): ThemeDefinition | undefined {\n return registry.get(name.trim().toLowerCase());\n}\n\nexport function clearThemeRegistryForTesting(): void {\n registry.clear();\n}\n","import type { PieceStyle, ThemeDefinition } from \"../types/types\";\nimport { ThemeError, ValidationError } from \"../types/errors\";\nimport { initializeBuiltInThemes } from \"./builtins\";\nimport { getTheme } from \"./registry\";\nimport { validateThemeDefinition } from \"./validation\";\n\ninterface ResolveThemeOptions {\n theme?: string | ThemeDefinition;\n style?: PieceStyle;\n}\n\nexport function resolveTheme({ theme, style }: ResolveThemeOptions): ThemeDefinition {\n initializeBuiltInThemes();\n\n if (typeof theme === \"object\" && theme !== null) {\n try {\n return validateThemeDefinition(theme);\n } catch (error) {\n if (error instanceof ThemeError) {\n throw error;\n }\n\n if (error instanceof ValidationError) {\n throw new ThemeError(error.message, { cause: error });\n }\n\n throw error;\n }\n }\n\n const requestedName = typeof theme === \"string\" ? theme : style ?? \"merida\";\n const resolvedTheme = getTheme(requestedName);\n\n if (!resolvedTheme) {\n throw new ThemeError(`Unknown theme: ${requestedName}`);\n }\n\n return resolvedTheme;\n}\n","import type {\n BoardColors,\n CoordinatesInput,\n CoordinatesOptions,\n CoordinatesPosition,\n Padding,\n RenderOptions,\n ResolvedColors,\n ResolvedCoordinates,\n ResolvedRenderOptions,\n Square,\n ThemeDefinition,\n} from \"../types/types\";\nimport { normalizeHighlights } from \"../core/highlights\";\nimport {\n normalizePadding,\n validateBoardColors,\n validateBorderSize,\n validateCoordinatesOption,\n validateSize,\n} from \"../core/validators\";\nimport { resolveTheme } from \"../themes/resolver\";\n\nexport const DEFAULT_SIZE = 480;\nexport const DEFAULT_PADDING: Padding = [0, 0, 0, 0];\nexport const DEFAULT_BORDER_SIZE = 0;\nexport const DEFAULT_COLORS: ResolvedColors = {\n lightSquare: \"#f0d9b5\",\n darkSquare: \"#b58863\",\n highlight: \"rgba(255, 206, 0, 0.45)\",\n};\nexport const DEFAULT_COORDINATES: ResolvedCoordinates = {\n enabled: false,\n position: \"inside\",\n};\n\nexport function normalizeColors(colors?: BoardColors): ResolvedColors {\n return {\n lightSquare: colors?.lightSquare ?? DEFAULT_COLORS.lightSquare,\n darkSquare: colors?.darkSquare ?? DEFAULT_COLORS.darkSquare,\n highlight: colors?.highlight ?? DEFAULT_COLORS.highlight,\n };\n}\n\nexport function normalizeCoordinates(\n coordinates: CoordinatesInput | undefined,\n borderSize: number,\n): ResolvedCoordinates {\n if (coordinates === undefined || coordinates === false) {\n return { ...DEFAULT_COORDINATES };\n }\n\n const defaultPosition: CoordinatesPosition =\n borderSize > 0 ? \"border\" : \"inside\";\n\n if (coordinates === true) {\n return {\n enabled: true,\n position: defaultPosition,\n color: defaultPosition === \"border\" ? \"#333\" : undefined,\n };\n }\n\n if (coordinates === \"border\" || coordinates === \"inside\") {\n return {\n enabled: true,\n position: coordinates,\n color: coordinates === \"border\" ? \"#333\" : undefined,\n };\n }\n\n const position = coordinates.position ?? defaultPosition;\n\n return {\n enabled: coordinates.enabled ?? true,\n position,\n color: coordinates.color ?? (position === \"border\" ? \"#333\" : undefined),\n };\n}\n\nexport function normalizeRenderInputs(\n options: RenderOptions & { highlightSquares?: Square[] },\n): ResolvedRenderOptions {\n const size = validateSize(options.size ?? DEFAULT_SIZE);\n const borderSize = validateBorderSize(\n options.borderSize ?? DEFAULT_BORDER_SIZE,\n size,\n );\n validateBoardColors(options.colors);\n validateCoordinatesOption(options.coordinates, borderSize);\n\n return {\n size,\n padding: normalizePadding(options.padding ?? DEFAULT_PADDING),\n borderSize,\n flipped: options.flipped ?? false,\n theme: resolveTheme({\n theme: options.theme,\n style: options.style,\n }),\n highlightSquares: normalizeHighlights(options.highlightSquares ?? []),\n colors: normalizeColors(options.colors),\n coordinates: normalizeCoordinates(options.coordinates, borderSize),\n };\n}\n","import { parseBoardArray, parseFEN, parsePGN } from \"../core/parsers\";\nimport { normalizeHighlights } from \"../core/highlights\";\nimport { ValidationError } from \"../types/errors\";\nimport type {\n BoardArray,\n ChessImageGeneratorOptions,\n RenderOptions,\n} from \"../types/types\";\nimport { CanvasPngRenderer } from \"../render/canvas-renderer\";\nimport { writeBufferToFile } from \"../utils/io\";\nimport { normalizeRenderInputs } from \"../utils/normalization\";\nimport type { BoardPosition } from \"../core/board\";\n\nexport class ChessImageGenerator {\n private position: BoardPosition | null = null;\n\n private readonly defaults: RenderOptions;\n\n private highlights: string[] = [];\n\n constructor(options: ChessImageGeneratorOptions = {}) {\n this.defaults = { ...options };\n normalizeRenderInputs({\n ...this.defaults,\n highlightSquares: [],\n });\n }\n\n async loadFEN(fen: string): Promise<void> {\n this.position = parseFEN(fen);\n this.clearHighlights();\n }\n\n async loadPGN(pgn: string): Promise<void> {\n this.position = parsePGN(pgn);\n this.clearHighlights();\n }\n\n async loadBoard(board: BoardArray): Promise<void> {\n this.position = parseBoardArray(board);\n this.clearHighlights();\n }\n\n setHighlights(squares: string[]): void {\n this.highlights = normalizeHighlights(squares);\n }\n\n clearHighlights(): void {\n this.highlights = [];\n }\n\n async toBuffer(): Promise<Buffer> {\n if (!this.position) {\n throw new ValidationError(\"No board position loaded\");\n }\n\n const renderer = new CanvasPngRenderer();\n const normalized = normalizeRenderInputs({\n ...this.defaults,\n highlightSquares: this.highlights,\n });\n\n return renderer.render({\n board: this.position,\n theme: normalized.theme,\n highlights: normalized.highlightSquares,\n size: normalized.size,\n padding: normalized.padding,\n borderSize: normalized.borderSize,\n flipped: normalized.flipped,\n colors: normalized.colors,\n coordinates: normalized.coordinates,\n });\n }\n\n async toFile(filePath: string): Promise<void> {\n const buffer = await this.toBuffer();\n await writeBufferToFile(filePath, buffer);\n }\n}\n","import { parseBoardArray, parseFEN, parsePGN } from \"../core/parsers\";\nimport { ValidationError } from \"../types/errors\";\nimport type { RenderChessOptions } from \"../types/types\";\nimport { CanvasPngRenderer } from \"../render/canvas-renderer\";\nimport { normalizeRenderInputs } from \"../utils/normalization\";\n\nfunction parseInputPosition(options: RenderChessOptions) {\n if (typeof options.fen === \"string\") {\n return parseFEN(options.fen);\n }\n\n if (typeof options.pgn === \"string\") {\n return parsePGN(options.pgn);\n }\n\n if (Array.isArray(options.board)) {\n return parseBoardArray(options.board);\n }\n\n throw new ValidationError(\"Exactly one of fen, pgn, or board must be provided\");\n}\n\nexport async function renderChess(options: RenderChessOptions): Promise<Buffer> {\n const provided = [\n typeof options.fen === \"string\" ? options.fen : undefined,\n typeof options.pgn === \"string\" ? options.pgn : undefined,\n Array.isArray(options.board) ? options.board : undefined,\n ].filter((value) => value !== undefined);\n\n if (provided.length !== 1) {\n throw new ValidationError(\"Exactly one of fen, pgn, or board must be provided\");\n }\n\n const position = parseInputPosition(options);\n const renderer = new CanvasPngRenderer();\n const normalized = normalizeRenderInputs(options);\n\n return renderer.render({\n board: position,\n theme: normalized.theme,\n highlights: normalized.highlightSquares,\n size: normalized.size,\n padding: normalized.padding,\n borderSize: normalized.borderSize,\n flipped: normalized.flipped,\n colors: normalized.colors,\n coordinates: normalized.coordinates,\n });\n}\n"],"mappings":"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","names":["import_canvas","import_canvas","import_promises"]}
|