chess2img 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,7 @@
20
20
  - Render PNG chessboard images from `fen`, `pgn`, or `board` input.
21
21
  - Use five bundled built-in themes: `merida`, `alpha`, `cburnett`, `cheq`, and `leipzig`.
22
22
  - Highlight squares such as the last move or key tactical ideas.
23
- - Customize board colors, size, padding, and board orientation.
23
+ - Customize board colors, size, padding, border sizing, coordinates, and board orientation.
24
24
  - Use either the functional `renderChess(...)` API or the `ChessImageGenerator` class API.
25
25
  - Register custom themes globally or pass a theme inline for one-off rendering.
26
26
  - Consume the package from both JavaScript and TypeScript projects.
@@ -89,6 +89,26 @@ const png = await renderChess({
89
89
  await writeFile("board.png", png);
90
90
  ```
91
91
 
92
+ ### Coordinates And Border
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
+ borderSize: 24,
103
+ coordinates: {
104
+ enabled: true,
105
+ color: "#333",
106
+ },
107
+ });
108
+
109
+ await writeFile("board-with-coordinates.png", png);
110
+ ```
111
+
92
112
  ### Class API
93
113
 
94
114
  ```ts
@@ -202,14 +222,18 @@ Semantics:
202
222
 
203
223
  - `size`: board size in pixels
204
224
  - `padding`: `[top, right, bottom, left]`
225
+ - `borderSize`: inner border size in pixels, from `0` up to `Math.floor(size / 8)`
205
226
  - `flipped`: render from black's perspective when `true`
206
227
  - `style`: built-in theme alias
207
228
  - `theme`: built-in theme name, registered custom theme name, or inline `ThemeDefinition`
208
229
  - `highlightSquares`: array of algebraic squares such as `["e4", "d5"]`
230
+ - `coordinates`: `boolean` or `{ enabled?: boolean; color?: string }`
209
231
  - `colors.lightSquare`
210
232
  - `colors.darkSquare`
211
233
  - `colors.highlight`
212
234
 
235
+ `coordinates: true` enables default coordinate labels. `coordinates: false` or omitting the option disables them. If coordinates are enabled while `borderSize` is `0`, rendering still succeeds but no labels are visible because no border band exists for them. At very small valid sizes, the renderer suppresses coordinates when they cannot fit legibly inside the available border bands.
236
+
213
237
  ### Errors
214
238
 
215
239
  The library exports:
package/dist/index.cjs CHANGED
@@ -81,8 +81,10 @@ function createEmptyBoardPosition() {
81
81
  }
82
82
 
83
83
  // src/core/validators.ts
84
+ var import_canvas = require("canvas");
84
85
  var SQUARE_PATTERN = /^[a-h][1-8]$/;
85
86
  var PIECE_PATTERN = /^[prnbqkPRNBQK]$/;
87
+ var colorValidationContext = (0, import_canvas.createCanvas)(1, 1).getContext("2d");
86
88
  function validateSize(size) {
87
89
  if (!Number.isFinite(size) || size <= 0) {
88
90
  throw new ValidationError(`Invalid board size: ${size}`);
@@ -135,6 +137,67 @@ function validateThemeName(name) {
135
137
  }
136
138
  return normalized;
137
139
  }
140
+ function validateBorderSize(borderSize, size) {
141
+ const normalizedSize = validateSize(size);
142
+ const normalizedBorderSize = Math.round(borderSize);
143
+ const maxBorderSize = Math.floor(normalizedSize / 8);
144
+ if (!Number.isFinite(borderSize) || normalizedBorderSize < 0) {
145
+ throw new ValidationError(`Invalid borderSize: ${borderSize}`);
146
+ }
147
+ if (normalizedBorderSize > maxBorderSize) {
148
+ throw new ValidationError(
149
+ `Invalid borderSize: ${borderSize}. Maximum allowed for size ${normalizedSize} is ${maxBorderSize}`
150
+ );
151
+ }
152
+ return normalizedBorderSize;
153
+ }
154
+ function validateColorString(color, label = "color") {
155
+ if (typeof color !== "string" || color.trim() === "") {
156
+ throw new ValidationError(`Invalid ${label}: ${String(color)}`);
157
+ }
158
+ const normalized = color.trim();
159
+ colorValidationContext.fillStyle = "#010203";
160
+ colorValidationContext.fillStyle = normalized;
161
+ const firstPass = String(colorValidationContext.fillStyle);
162
+ colorValidationContext.fillStyle = "#fefefe";
163
+ colorValidationContext.fillStyle = normalized;
164
+ const secondPass = String(colorValidationContext.fillStyle);
165
+ if (firstPass !== secondPass) {
166
+ throw new ValidationError(`Invalid ${label}: ${color}`);
167
+ }
168
+ return normalized;
169
+ }
170
+ function validateBoardColors(colors) {
171
+ if (!colors) {
172
+ return;
173
+ }
174
+ if (colors.lightSquare !== void 0) {
175
+ validateColorString(colors.lightSquare, "lightSquare color");
176
+ }
177
+ if (colors.darkSquare !== void 0) {
178
+ validateColorString(colors.darkSquare, "darkSquare color");
179
+ }
180
+ if (colors.highlight !== void 0) {
181
+ validateColorString(colors.highlight, "highlight color");
182
+ }
183
+ }
184
+ function isCoordinatesOptions(value) {
185
+ return typeof value === "object" && value !== null && !Array.isArray(value);
186
+ }
187
+ function validateCoordinatesOption(coordinates) {
188
+ if (coordinates === void 0 || typeof coordinates === "boolean") {
189
+ return;
190
+ }
191
+ if (!isCoordinatesOptions(coordinates)) {
192
+ throw new ValidationError("coordinates must be a boolean or an options object");
193
+ }
194
+ if (coordinates.enabled !== void 0 && typeof coordinates.enabled !== "boolean") {
195
+ throw new ValidationError("coordinates.enabled must be a boolean");
196
+ }
197
+ if (coordinates.color !== void 0) {
198
+ validateColorString(coordinates.color, "coordinates.color");
199
+ }
200
+ }
138
201
 
139
202
  // src/core/parsers.ts
140
203
  var PIECE_SYMBOL_TO_KEY = {
@@ -204,32 +267,57 @@ function normalizeHighlights(input) {
204
267
  }
205
268
 
206
269
  // src/render/canvas-renderer.ts
207
- var import_canvas2 = require("canvas");
270
+ var import_canvas3 = require("canvas");
208
271
 
209
272
  // src/core/geometry.ts
210
273
  function createBoardGeometry({
211
274
  size,
212
275
  padding,
276
+ borderSize,
213
277
  flipped
214
278
  }) {
215
279
  const [top, right, bottom, left] = padding;
216
- const squareSize = size / 8;
280
+ const boardOuterSize = size;
281
+ const boardOuterX = left;
282
+ const boardOuterY = top;
283
+ const boardX = left + borderSize;
284
+ const boardY = top + borderSize;
285
+ const boardSize = size - borderSize * 2;
286
+ const squareSize = boardSize / 8;
217
287
  const squares = Object.fromEntries(
218
288
  SQUARES.map((square, index) => {
219
289
  const fileIndex = index % 8;
220
290
  const rankIndex = Math.floor(index / 8);
221
- const x = left + (flipped ? 7 - fileIndex : fileIndex) * squareSize;
222
- const y = top + (flipped ? 7 - rankIndex : rankIndex) * squareSize;
291
+ const x = boardX + (flipped ? 7 - fileIndex : fileIndex) * squareSize;
292
+ const y = boardY + (flipped ? 7 - rankIndex : rankIndex) * squareSize;
223
293
  return [square, { x, y, size: squareSize }];
224
294
  })
225
295
  );
296
+ const displayedFiles = flipped ? [...FILES].reverse() : [...FILES];
297
+ const displayedRanks = flipped ? [...RANKS].reverse() : [...RANKS];
298
+ const fileLabels = borderSize ? displayedFiles.map((file, fileIndex) => ({
299
+ text: file,
300
+ x: boardX + fileIndex * squareSize + squareSize / 2,
301
+ y: boardOuterY + boardOuterSize - borderSize / 2
302
+ })) : [];
303
+ const rankLabels = borderSize ? displayedRanks.map((rank, rankIndex) => ({
304
+ text: rank,
305
+ x: boardOuterX + borderSize / 2,
306
+ y: boardY + rankIndex * squareSize + squareSize / 2
307
+ })) : [];
226
308
  return {
227
309
  imageWidth: left + size + right,
228
310
  imageHeight: top + size + bottom,
229
311
  squareSize,
230
- boardX: left,
231
- boardY: top,
232
- boardSize: size,
312
+ borderSize,
313
+ boardOuterX,
314
+ boardOuterY,
315
+ boardOuterSize,
316
+ boardX,
317
+ boardY,
318
+ boardSize,
319
+ fileLabels,
320
+ rankLabels,
233
321
  squares
234
322
  };
235
323
  }
@@ -259,7 +347,7 @@ var SourceAssetCache = class {
259
347
 
260
348
  // src/render/rasterizer.ts
261
349
  var import_promises = require("fs/promises");
262
- var import_canvas = require("canvas");
350
+ var import_canvas2 = require("canvas");
263
351
  var import_resvg_js = require("@resvg/resvg-js");
264
352
  var svgSourceCache = new SourceAssetCache();
265
353
  var imageBufferCache = new SourceAssetCache();
@@ -299,8 +387,8 @@ async function rasterizeSvgAsset(filePath, squareSize) {
299
387
  }
300
388
  });
301
389
  const pngBuffer = resvg.render().asPng();
302
- const image = await (0, import_canvas.loadImage)(pngBuffer);
303
- const canvas = (0, import_canvas.createCanvas)(squareSize, squareSize);
390
+ const image = await (0, import_canvas2.loadImage)(pngBuffer);
391
+ const canvas = (0, import_canvas2.createCanvas)(squareSize, squareSize);
304
392
  const context = canvas.getContext("2d");
305
393
  context.drawImage(image, 0, 0, squareSize, squareSize);
306
394
  return canvas;
@@ -311,8 +399,8 @@ async function rasterizeSvgAsset(filePath, squareSize) {
311
399
  async function rasterizePngAsset(filePath, squareSize) {
312
400
  try {
313
401
  const pngSource = await readBinaryAsset(filePath);
314
- const image = await (0, import_canvas.loadImage)(pngSource);
315
- const canvas = (0, import_canvas.createCanvas)(squareSize, squareSize);
402
+ const image = await (0, import_canvas2.loadImage)(pngSource);
403
+ const canvas = (0, import_canvas2.createCanvas)(squareSize, squareSize);
316
404
  const context = canvas.getContext("2d");
317
405
  context.drawImage(image, 0, 0, squareSize, squareSize);
318
406
  return canvas;
@@ -329,6 +417,10 @@ async function rasterizeThemeAsset(asset, squareSize) {
329
417
 
330
418
  // src/render/canvas-renderer.ts
331
419
  var pieceRasterCache = new RasterAssetCache();
420
+ var MIN_COORDINATE_FONT_SIZE = 8;
421
+ var MAX_FILE_LABEL_WIDTH_RATIO = 0.75;
422
+ var MAX_RANK_LABEL_WIDTH_RATIO = 0.7;
423
+ var MAX_LABEL_HEIGHT_RATIO = 0.7;
332
424
  function isDarkSquare(square) {
333
425
  const fileIndex = square.charCodeAt(0) - 97;
334
426
  const rankNumber = Number(square[1]);
@@ -344,15 +436,55 @@ async function getPieceRaster(themeName, pieceKey, asset, squareSize) {
344
436
  pieceRasterCache.set(cacheKey, raster);
345
437
  return raster;
346
438
  }
439
+ function drawCoordinates(context, request, geometry) {
440
+ if (!request.coordinates.enabled || geometry.borderSize === 0) {
441
+ return;
442
+ }
443
+ const maxFontSize = Math.floor(
444
+ Math.min(geometry.squareSize * 0.6, geometry.borderSize * 0.65)
445
+ );
446
+ let fontSize = null;
447
+ for (let candidate = maxFontSize; candidate >= MIN_COORDINATE_FONT_SIZE; candidate -= 1) {
448
+ context.font = `${candidate}px sans-serif`;
449
+ const filesFit = geometry.fileLabels.every((label) => {
450
+ const metrics = context.measureText(label.text);
451
+ const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
452
+ return metrics.width <= geometry.squareSize * MAX_FILE_LABEL_WIDTH_RATIO && textHeight <= geometry.borderSize * MAX_LABEL_HEIGHT_RATIO;
453
+ });
454
+ const ranksFit = geometry.rankLabels.every((label) => {
455
+ const metrics = context.measureText(label.text);
456
+ const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
457
+ return metrics.width <= geometry.borderSize * MAX_RANK_LABEL_WIDTH_RATIO && textHeight <= geometry.squareSize * MAX_LABEL_HEIGHT_RATIO;
458
+ });
459
+ if (filesFit && ranksFit) {
460
+ fontSize = candidate;
461
+ break;
462
+ }
463
+ }
464
+ if (fontSize === null) {
465
+ return;
466
+ }
467
+ context.fillStyle = request.coordinates.color;
468
+ context.font = `${fontSize}px sans-serif`;
469
+ context.textAlign = "center";
470
+ context.textBaseline = "middle";
471
+ for (const label of geometry.fileLabels) {
472
+ context.fillText(label.text, label.x, label.y);
473
+ }
474
+ for (const label of geometry.rankLabels) {
475
+ context.fillText(label.text, label.x, label.y);
476
+ }
477
+ }
347
478
  var CanvasPngRenderer = class {
348
479
  async render(request) {
349
480
  try {
350
481
  const geometry = createBoardGeometry({
351
482
  size: request.size,
352
483
  padding: request.padding,
484
+ borderSize: request.borderSize,
353
485
  flipped: request.flipped
354
486
  });
355
- const canvas = (0, import_canvas2.createCanvas)(geometry.imageWidth, geometry.imageHeight);
487
+ const canvas = (0, import_canvas3.createCanvas)(geometry.imageWidth, geometry.imageHeight);
356
488
  const context = canvas.getContext("2d");
357
489
  context.fillStyle = request.colors.lightSquare;
358
490
  context.fillRect(0, 0, geometry.imageWidth, geometry.imageHeight);
@@ -392,6 +524,7 @@ var CanvasPngRenderer = class {
392
524
  squareGeometry.size
393
525
  );
394
526
  }
527
+ drawCoordinates(context, request, geometry);
395
528
  return canvas.toBuffer("image/png");
396
529
  } catch (error) {
397
530
  if (error instanceof RenderError) {
@@ -554,11 +687,16 @@ function resolveTheme({ theme, style }) {
554
687
  // src/utils/normalization.ts
555
688
  var DEFAULT_SIZE = 480;
556
689
  var DEFAULT_PADDING = [0, 0, 0, 0];
690
+ var DEFAULT_BORDER_SIZE = 0;
557
691
  var DEFAULT_COLORS = {
558
692
  lightSquare: "#f0d9b5",
559
693
  darkSquare: "#b58863",
560
694
  highlight: "rgba(255, 206, 0, 0.45)"
561
695
  };
696
+ var DEFAULT_COORDINATES = {
697
+ enabled: false,
698
+ color: "#333"
699
+ };
562
700
  function normalizeColors(colors) {
563
701
  return {
564
702
  lightSquare: colors?.lightSquare ?? DEFAULT_COLORS.lightSquare,
@@ -566,17 +704,41 @@ function normalizeColors(colors) {
566
704
  highlight: colors?.highlight ?? DEFAULT_COLORS.highlight
567
705
  };
568
706
  }
707
+ function normalizeCoordinates(coordinates) {
708
+ if (coordinates === void 0 || coordinates === false) {
709
+ return { ...DEFAULT_COORDINATES };
710
+ }
711
+ if (coordinates === true) {
712
+ return {
713
+ enabled: true,
714
+ color: DEFAULT_COORDINATES.color
715
+ };
716
+ }
717
+ return {
718
+ enabled: coordinates.enabled ?? true,
719
+ color: coordinates.color ?? DEFAULT_COORDINATES.color
720
+ };
721
+ }
569
722
  function normalizeRenderInputs(options) {
723
+ const size = validateSize(options.size ?? DEFAULT_SIZE);
724
+ const borderSize = validateBorderSize(
725
+ options.borderSize ?? DEFAULT_BORDER_SIZE,
726
+ size
727
+ );
728
+ validateBoardColors(options.colors);
729
+ validateCoordinatesOption(options.coordinates);
570
730
  return {
571
- size: validateSize(options.size ?? DEFAULT_SIZE),
731
+ size,
572
732
  padding: normalizePadding(options.padding ?? DEFAULT_PADDING),
733
+ borderSize,
573
734
  flipped: options.flipped ?? false,
574
735
  theme: resolveTheme({
575
736
  theme: options.theme,
576
737
  style: options.style
577
738
  }),
578
739
  highlightSquares: normalizeHighlights(options.highlightSquares ?? []),
579
- colors: normalizeColors(options.colors)
740
+ colors: normalizeColors(options.colors),
741
+ coordinates: normalizeCoordinates(options.coordinates)
580
742
  };
581
743
  }
582
744
 
@@ -625,8 +787,10 @@ var ChessImageGenerator = class {
625
787
  highlights: normalized.highlightSquares,
626
788
  size: normalized.size,
627
789
  padding: normalized.padding,
790
+ borderSize: normalized.borderSize,
628
791
  flipped: normalized.flipped,
629
- colors: normalized.colors
792
+ colors: normalized.colors,
793
+ coordinates: normalized.coordinates
630
794
  });
631
795
  }
632
796
  async toFile(filePath) {
@@ -666,8 +830,10 @@ async function renderChess(options) {
666
830
  highlights: normalized.highlightSquares,
667
831
  size: normalized.size,
668
832
  padding: normalized.padding,
833
+ borderSize: normalized.borderSize,
669
834
  flipped: normalized.flipped,
670
- colors: normalized.colors
835
+ colors: normalized.colors,
836
+ coordinates: normalized.coordinates
671
837
  });
672
838
  }
673
839
  // Annotate the CommonJS export names for ESM import in node:
@@ -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 type { BoardArray, BoardCell, Padding, Square } 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)$/;\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","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>>>();\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\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 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 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 { SQUARES } from \"./board\";\n\nexport interface SquareGeometry {\n x: number;\n y: number;\n size: number;\n}\n\nexport interface BoardGeometry {\n imageWidth: number;\n imageHeight: number;\n squareSize: number;\n boardX: number;\n boardY: number;\n boardSize: number;\n squares: Record<Square, SquareGeometry>;\n}\n\ninterface BoardGeometryOptions {\n size: number;\n padding: Padding;\n flipped: boolean;\n}\n\nexport function createBoardGeometry({\n size,\n padding,\n flipped,\n}: BoardGeometryOptions): BoardGeometry {\n const [top, right, bottom, left] = padding;\n const squareSize = size / 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 = left + (flipped ? 7 - fileIndex : fileIndex) * squareSize;\n const y = top + (flipped ? 7 - rankIndex : rankIndex) * squareSize;\n\n return [square, { x, y, size: squareSize }];\n }),\n ) as Record<Square, SquareGeometry>;\n\n return {\n imageWidth: left + size + right,\n imageHeight: top + size + bottom,\n squareSize,\n boardX: left,\n boardY: top,\n boardSize: size,\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 Padding,\n RenderOptions,\n ResolvedColors,\n Square,\n ThemeDefinition,\n} from \"../types/types\";\nimport { normalizeHighlights } from \"../core/highlights\";\nimport { normalizePadding, validateSize } 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_COLORS: ResolvedColors = {\n lightSquare: \"#f0d9b5\",\n darkSquare: \"#b58863\",\n highlight: \"rgba(255, 206, 0, 0.45)\",\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 normalizeRenderInputs(options: RenderOptions & { highlightSquares?: Square[] }): {\n size: number;\n padding: Padding;\n flipped: boolean;\n theme: ThemeDefinition;\n highlightSquares: Square[];\n colors: ResolvedColors;\n} {\n return {\n size: validateSize(options.size ?? DEFAULT_SIZE),\n padding: normalizePadding(options.padding ?? DEFAULT_PADDING),\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 };\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 flipped: normalized.flipped,\n colors: normalized.colors,\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 flipped: normalized.flipped,\n colors: normalized.colors,\n });\n}\n"],"mappings":"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","names":["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 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"]}
package/dist/index.d.cts CHANGED
@@ -51,14 +51,20 @@ interface BoardColors {
51
51
  darkSquare?: string;
52
52
  highlight?: string;
53
53
  }
54
+ interface CoordinatesOptions {
55
+ enabled?: boolean;
56
+ color?: string;
57
+ }
54
58
  interface RenderOptions {
55
59
  size?: number;
56
60
  padding?: Padding;
61
+ borderSize?: number;
57
62
  flipped?: boolean;
58
63
  style?: PieceStyle;
59
64
  theme?: string | ThemeDefinition;
60
65
  highlightSquares?: Square[];
61
66
  colors?: BoardColors;
67
+ coordinates?: boolean | CoordinatesOptions;
62
68
  }
63
69
  interface ChessImageGeneratorOptions extends RenderOptions {
64
70
  }
@@ -67,13 +73,19 @@ interface ResolvedColors {
67
73
  darkSquare: string;
68
74
  highlight: string;
69
75
  }
76
+ interface ResolvedCoordinates {
77
+ enabled: boolean;
78
+ color: string;
79
+ }
70
80
  interface ResolvedRenderOptions {
71
81
  size: number;
72
82
  padding: Padding;
83
+ borderSize: number;
73
84
  flipped: boolean;
74
85
  theme: ThemeDefinition;
75
86
  highlightSquares: Square[];
76
87
  colors: ResolvedColors;
88
+ coordinates: ResolvedCoordinates;
77
89
  }
78
90
  interface FENRenderInput extends RenderOptions {
79
91
  fen: string;
@@ -110,4 +122,4 @@ declare function renderChess(options: RenderChessOptions): Promise<Buffer>;
110
122
 
111
123
  declare function registerTheme(theme: ThemeDefinition): ThemeDefinition;
112
124
 
113
- export { type BoardArray, type BoardCell, type BoardColors, ChessImageGenerator, type ChessImageGeneratorOptions, IOError, type Padding, ParseError, type PieceKey, type PieceStyle, type PngAssetSource, type RenderChessOptions, RenderError, type RenderOptions, type ResolvedColors, type ResolvedRenderOptions, type Square, type SvgAssetSource, type ThemeAssetSource, type ThemeDefinition, ThemeError, ValidationError, registerTheme, renderChess };
125
+ export { type BoardArray, type BoardCell, type BoardColors, ChessImageGenerator, type ChessImageGeneratorOptions, type CoordinatesOptions, IOError, type Padding, ParseError, type PieceKey, type PieceStyle, type PngAssetSource, type RenderChessOptions, RenderError, type RenderOptions, type ResolvedColors, type ResolvedCoordinates, type ResolvedRenderOptions, type Square, type SvgAssetSource, type ThemeAssetSource, type ThemeDefinition, ThemeError, ValidationError, registerTheme, renderChess };
package/dist/index.d.ts CHANGED
@@ -51,14 +51,20 @@ interface BoardColors {
51
51
  darkSquare?: string;
52
52
  highlight?: string;
53
53
  }
54
+ interface CoordinatesOptions {
55
+ enabled?: boolean;
56
+ color?: string;
57
+ }
54
58
  interface RenderOptions {
55
59
  size?: number;
56
60
  padding?: Padding;
61
+ borderSize?: number;
57
62
  flipped?: boolean;
58
63
  style?: PieceStyle;
59
64
  theme?: string | ThemeDefinition;
60
65
  highlightSquares?: Square[];
61
66
  colors?: BoardColors;
67
+ coordinates?: boolean | CoordinatesOptions;
62
68
  }
63
69
  interface ChessImageGeneratorOptions extends RenderOptions {
64
70
  }
@@ -67,13 +73,19 @@ interface ResolvedColors {
67
73
  darkSquare: string;
68
74
  highlight: string;
69
75
  }
76
+ interface ResolvedCoordinates {
77
+ enabled: boolean;
78
+ color: string;
79
+ }
70
80
  interface ResolvedRenderOptions {
71
81
  size: number;
72
82
  padding: Padding;
83
+ borderSize: number;
73
84
  flipped: boolean;
74
85
  theme: ThemeDefinition;
75
86
  highlightSquares: Square[];
76
87
  colors: ResolvedColors;
88
+ coordinates: ResolvedCoordinates;
77
89
  }
78
90
  interface FENRenderInput extends RenderOptions {
79
91
  fen: string;
@@ -110,4 +122,4 @@ declare function renderChess(options: RenderChessOptions): Promise<Buffer>;
110
122
 
111
123
  declare function registerTheme(theme: ThemeDefinition): ThemeDefinition;
112
124
 
113
- export { type BoardArray, type BoardCell, type BoardColors, ChessImageGenerator, type ChessImageGeneratorOptions, IOError, type Padding, ParseError, type PieceKey, type PieceStyle, type PngAssetSource, type RenderChessOptions, RenderError, type RenderOptions, type ResolvedColors, type ResolvedRenderOptions, type Square, type SvgAssetSource, type ThemeAssetSource, type ThemeDefinition, ThemeError, ValidationError, registerTheme, renderChess };
125
+ export { type BoardArray, type BoardCell, type BoardColors, ChessImageGenerator, type ChessImageGeneratorOptions, type CoordinatesOptions, IOError, type Padding, ParseError, type PieceKey, type PieceStyle, type PngAssetSource, type RenderChessOptions, RenderError, type RenderOptions, type ResolvedColors, type ResolvedCoordinates, type ResolvedRenderOptions, type Square, type SvgAssetSource, type ThemeAssetSource, type ThemeDefinition, ThemeError, ValidationError, registerTheme, renderChess };
package/dist/index.js CHANGED
@@ -55,8 +55,10 @@ function createEmptyBoardPosition() {
55
55
  }
56
56
 
57
57
  // src/core/validators.ts
58
+ import { createCanvas } from "canvas";
58
59
  var SQUARE_PATTERN = /^[a-h][1-8]$/;
59
60
  var PIECE_PATTERN = /^[prnbqkPRNBQK]$/;
61
+ var colorValidationContext = createCanvas(1, 1).getContext("2d");
60
62
  function validateSize(size) {
61
63
  if (!Number.isFinite(size) || size <= 0) {
62
64
  throw new ValidationError(`Invalid board size: ${size}`);
@@ -109,6 +111,67 @@ function validateThemeName(name) {
109
111
  }
110
112
  return normalized;
111
113
  }
114
+ function validateBorderSize(borderSize, size) {
115
+ const normalizedSize = validateSize(size);
116
+ const normalizedBorderSize = Math.round(borderSize);
117
+ const maxBorderSize = Math.floor(normalizedSize / 8);
118
+ if (!Number.isFinite(borderSize) || normalizedBorderSize < 0) {
119
+ throw new ValidationError(`Invalid borderSize: ${borderSize}`);
120
+ }
121
+ if (normalizedBorderSize > maxBorderSize) {
122
+ throw new ValidationError(
123
+ `Invalid borderSize: ${borderSize}. Maximum allowed for size ${normalizedSize} is ${maxBorderSize}`
124
+ );
125
+ }
126
+ return normalizedBorderSize;
127
+ }
128
+ function validateColorString(color, label = "color") {
129
+ if (typeof color !== "string" || color.trim() === "") {
130
+ throw new ValidationError(`Invalid ${label}: ${String(color)}`);
131
+ }
132
+ const normalized = color.trim();
133
+ colorValidationContext.fillStyle = "#010203";
134
+ colorValidationContext.fillStyle = normalized;
135
+ const firstPass = String(colorValidationContext.fillStyle);
136
+ colorValidationContext.fillStyle = "#fefefe";
137
+ colorValidationContext.fillStyle = normalized;
138
+ const secondPass = String(colorValidationContext.fillStyle);
139
+ if (firstPass !== secondPass) {
140
+ throw new ValidationError(`Invalid ${label}: ${color}`);
141
+ }
142
+ return normalized;
143
+ }
144
+ function validateBoardColors(colors) {
145
+ if (!colors) {
146
+ return;
147
+ }
148
+ if (colors.lightSquare !== void 0) {
149
+ validateColorString(colors.lightSquare, "lightSquare color");
150
+ }
151
+ if (colors.darkSquare !== void 0) {
152
+ validateColorString(colors.darkSquare, "darkSquare color");
153
+ }
154
+ if (colors.highlight !== void 0) {
155
+ validateColorString(colors.highlight, "highlight color");
156
+ }
157
+ }
158
+ function isCoordinatesOptions(value) {
159
+ return typeof value === "object" && value !== null && !Array.isArray(value);
160
+ }
161
+ function validateCoordinatesOption(coordinates) {
162
+ if (coordinates === void 0 || typeof coordinates === "boolean") {
163
+ return;
164
+ }
165
+ if (!isCoordinatesOptions(coordinates)) {
166
+ throw new ValidationError("coordinates must be a boolean or an options object");
167
+ }
168
+ if (coordinates.enabled !== void 0 && typeof coordinates.enabled !== "boolean") {
169
+ throw new ValidationError("coordinates.enabled must be a boolean");
170
+ }
171
+ if (coordinates.color !== void 0) {
172
+ validateColorString(coordinates.color, "coordinates.color");
173
+ }
174
+ }
112
175
 
113
176
  // src/core/parsers.ts
114
177
  var PIECE_SYMBOL_TO_KEY = {
@@ -178,32 +241,57 @@ function normalizeHighlights(input) {
178
241
  }
179
242
 
180
243
  // src/render/canvas-renderer.ts
181
- import { createCanvas as createCanvas2 } from "canvas";
244
+ import { createCanvas as createCanvas3 } from "canvas";
182
245
 
183
246
  // src/core/geometry.ts
184
247
  function createBoardGeometry({
185
248
  size,
186
249
  padding,
250
+ borderSize,
187
251
  flipped
188
252
  }) {
189
253
  const [top, right, bottom, left] = padding;
190
- const squareSize = size / 8;
254
+ const boardOuterSize = size;
255
+ const boardOuterX = left;
256
+ const boardOuterY = top;
257
+ const boardX = left + borderSize;
258
+ const boardY = top + borderSize;
259
+ const boardSize = size - borderSize * 2;
260
+ const squareSize = boardSize / 8;
191
261
  const squares = Object.fromEntries(
192
262
  SQUARES.map((square, index) => {
193
263
  const fileIndex = index % 8;
194
264
  const rankIndex = Math.floor(index / 8);
195
- const x = left + (flipped ? 7 - fileIndex : fileIndex) * squareSize;
196
- const y = top + (flipped ? 7 - rankIndex : rankIndex) * squareSize;
265
+ const x = boardX + (flipped ? 7 - fileIndex : fileIndex) * squareSize;
266
+ const y = boardY + (flipped ? 7 - rankIndex : rankIndex) * squareSize;
197
267
  return [square, { x, y, size: squareSize }];
198
268
  })
199
269
  );
270
+ const displayedFiles = flipped ? [...FILES].reverse() : [...FILES];
271
+ const displayedRanks = flipped ? [...RANKS].reverse() : [...RANKS];
272
+ const fileLabels = borderSize ? displayedFiles.map((file, fileIndex) => ({
273
+ text: file,
274
+ x: boardX + fileIndex * squareSize + squareSize / 2,
275
+ y: boardOuterY + boardOuterSize - borderSize / 2
276
+ })) : [];
277
+ const rankLabels = borderSize ? displayedRanks.map((rank, rankIndex) => ({
278
+ text: rank,
279
+ x: boardOuterX + borderSize / 2,
280
+ y: boardY + rankIndex * squareSize + squareSize / 2
281
+ })) : [];
200
282
  return {
201
283
  imageWidth: left + size + right,
202
284
  imageHeight: top + size + bottom,
203
285
  squareSize,
204
- boardX: left,
205
- boardY: top,
206
- boardSize: size,
286
+ borderSize,
287
+ boardOuterX,
288
+ boardOuterY,
289
+ boardOuterSize,
290
+ boardX,
291
+ boardY,
292
+ boardSize,
293
+ fileLabels,
294
+ rankLabels,
207
295
  squares
208
296
  };
209
297
  }
@@ -233,7 +321,7 @@ var SourceAssetCache = class {
233
321
 
234
322
  // src/render/rasterizer.ts
235
323
  import { readFile } from "fs/promises";
236
- import { createCanvas, loadImage } from "canvas";
324
+ import { createCanvas as createCanvas2, loadImage } from "canvas";
237
325
  import { Resvg } from "@resvg/resvg-js";
238
326
  var svgSourceCache = new SourceAssetCache();
239
327
  var imageBufferCache = new SourceAssetCache();
@@ -274,7 +362,7 @@ async function rasterizeSvgAsset(filePath, squareSize) {
274
362
  });
275
363
  const pngBuffer = resvg.render().asPng();
276
364
  const image = await loadImage(pngBuffer);
277
- const canvas = createCanvas(squareSize, squareSize);
365
+ const canvas = createCanvas2(squareSize, squareSize);
278
366
  const context = canvas.getContext("2d");
279
367
  context.drawImage(image, 0, 0, squareSize, squareSize);
280
368
  return canvas;
@@ -286,7 +374,7 @@ async function rasterizePngAsset(filePath, squareSize) {
286
374
  try {
287
375
  const pngSource = await readBinaryAsset(filePath);
288
376
  const image = await loadImage(pngSource);
289
- const canvas = createCanvas(squareSize, squareSize);
377
+ const canvas = createCanvas2(squareSize, squareSize);
290
378
  const context = canvas.getContext("2d");
291
379
  context.drawImage(image, 0, 0, squareSize, squareSize);
292
380
  return canvas;
@@ -303,6 +391,10 @@ async function rasterizeThemeAsset(asset, squareSize) {
303
391
 
304
392
  // src/render/canvas-renderer.ts
305
393
  var pieceRasterCache = new RasterAssetCache();
394
+ var MIN_COORDINATE_FONT_SIZE = 8;
395
+ var MAX_FILE_LABEL_WIDTH_RATIO = 0.75;
396
+ var MAX_RANK_LABEL_WIDTH_RATIO = 0.7;
397
+ var MAX_LABEL_HEIGHT_RATIO = 0.7;
306
398
  function isDarkSquare(square) {
307
399
  const fileIndex = square.charCodeAt(0) - 97;
308
400
  const rankNumber = Number(square[1]);
@@ -318,15 +410,55 @@ async function getPieceRaster(themeName, pieceKey, asset, squareSize) {
318
410
  pieceRasterCache.set(cacheKey, raster);
319
411
  return raster;
320
412
  }
413
+ function drawCoordinates(context, request, geometry) {
414
+ if (!request.coordinates.enabled || geometry.borderSize === 0) {
415
+ return;
416
+ }
417
+ const maxFontSize = Math.floor(
418
+ Math.min(geometry.squareSize * 0.6, geometry.borderSize * 0.65)
419
+ );
420
+ let fontSize = null;
421
+ for (let candidate = maxFontSize; candidate >= MIN_COORDINATE_FONT_SIZE; candidate -= 1) {
422
+ context.font = `${candidate}px sans-serif`;
423
+ const filesFit = geometry.fileLabels.every((label) => {
424
+ const metrics = context.measureText(label.text);
425
+ const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
426
+ return metrics.width <= geometry.squareSize * MAX_FILE_LABEL_WIDTH_RATIO && textHeight <= geometry.borderSize * MAX_LABEL_HEIGHT_RATIO;
427
+ });
428
+ const ranksFit = geometry.rankLabels.every((label) => {
429
+ const metrics = context.measureText(label.text);
430
+ const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
431
+ return metrics.width <= geometry.borderSize * MAX_RANK_LABEL_WIDTH_RATIO && textHeight <= geometry.squareSize * MAX_LABEL_HEIGHT_RATIO;
432
+ });
433
+ if (filesFit && ranksFit) {
434
+ fontSize = candidate;
435
+ break;
436
+ }
437
+ }
438
+ if (fontSize === null) {
439
+ return;
440
+ }
441
+ context.fillStyle = request.coordinates.color;
442
+ context.font = `${fontSize}px sans-serif`;
443
+ context.textAlign = "center";
444
+ context.textBaseline = "middle";
445
+ for (const label of geometry.fileLabels) {
446
+ context.fillText(label.text, label.x, label.y);
447
+ }
448
+ for (const label of geometry.rankLabels) {
449
+ context.fillText(label.text, label.x, label.y);
450
+ }
451
+ }
321
452
  var CanvasPngRenderer = class {
322
453
  async render(request) {
323
454
  try {
324
455
  const geometry = createBoardGeometry({
325
456
  size: request.size,
326
457
  padding: request.padding,
458
+ borderSize: request.borderSize,
327
459
  flipped: request.flipped
328
460
  });
329
- const canvas = createCanvas2(geometry.imageWidth, geometry.imageHeight);
461
+ const canvas = createCanvas3(geometry.imageWidth, geometry.imageHeight);
330
462
  const context = canvas.getContext("2d");
331
463
  context.fillStyle = request.colors.lightSquare;
332
464
  context.fillRect(0, 0, geometry.imageWidth, geometry.imageHeight);
@@ -366,6 +498,7 @@ var CanvasPngRenderer = class {
366
498
  squareGeometry.size
367
499
  );
368
500
  }
501
+ drawCoordinates(context, request, geometry);
369
502
  return canvas.toBuffer("image/png");
370
503
  } catch (error) {
371
504
  if (error instanceof RenderError) {
@@ -528,11 +661,16 @@ function resolveTheme({ theme, style }) {
528
661
  // src/utils/normalization.ts
529
662
  var DEFAULT_SIZE = 480;
530
663
  var DEFAULT_PADDING = [0, 0, 0, 0];
664
+ var DEFAULT_BORDER_SIZE = 0;
531
665
  var DEFAULT_COLORS = {
532
666
  lightSquare: "#f0d9b5",
533
667
  darkSquare: "#b58863",
534
668
  highlight: "rgba(255, 206, 0, 0.45)"
535
669
  };
670
+ var DEFAULT_COORDINATES = {
671
+ enabled: false,
672
+ color: "#333"
673
+ };
536
674
  function normalizeColors(colors) {
537
675
  return {
538
676
  lightSquare: colors?.lightSquare ?? DEFAULT_COLORS.lightSquare,
@@ -540,17 +678,41 @@ function normalizeColors(colors) {
540
678
  highlight: colors?.highlight ?? DEFAULT_COLORS.highlight
541
679
  };
542
680
  }
681
+ function normalizeCoordinates(coordinates) {
682
+ if (coordinates === void 0 || coordinates === false) {
683
+ return { ...DEFAULT_COORDINATES };
684
+ }
685
+ if (coordinates === true) {
686
+ return {
687
+ enabled: true,
688
+ color: DEFAULT_COORDINATES.color
689
+ };
690
+ }
691
+ return {
692
+ enabled: coordinates.enabled ?? true,
693
+ color: coordinates.color ?? DEFAULT_COORDINATES.color
694
+ };
695
+ }
543
696
  function normalizeRenderInputs(options) {
697
+ const size = validateSize(options.size ?? DEFAULT_SIZE);
698
+ const borderSize = validateBorderSize(
699
+ options.borderSize ?? DEFAULT_BORDER_SIZE,
700
+ size
701
+ );
702
+ validateBoardColors(options.colors);
703
+ validateCoordinatesOption(options.coordinates);
544
704
  return {
545
- size: validateSize(options.size ?? DEFAULT_SIZE),
705
+ size,
546
706
  padding: normalizePadding(options.padding ?? DEFAULT_PADDING),
707
+ borderSize,
547
708
  flipped: options.flipped ?? false,
548
709
  theme: resolveTheme({
549
710
  theme: options.theme,
550
711
  style: options.style
551
712
  }),
552
713
  highlightSquares: normalizeHighlights(options.highlightSquares ?? []),
553
- colors: normalizeColors(options.colors)
714
+ colors: normalizeColors(options.colors),
715
+ coordinates: normalizeCoordinates(options.coordinates)
554
716
  };
555
717
  }
556
718
 
@@ -599,8 +761,10 @@ var ChessImageGenerator = class {
599
761
  highlights: normalized.highlightSquares,
600
762
  size: normalized.size,
601
763
  padding: normalized.padding,
764
+ borderSize: normalized.borderSize,
602
765
  flipped: normalized.flipped,
603
- colors: normalized.colors
766
+ colors: normalized.colors,
767
+ coordinates: normalized.coordinates
604
768
  });
605
769
  }
606
770
  async toFile(filePath) {
@@ -640,8 +804,10 @@ async function renderChess(options) {
640
804
  highlights: normalized.highlightSquares,
641
805
  size: normalized.size,
642
806
  padding: normalized.padding,
807
+ borderSize: normalized.borderSize,
643
808
  flipped: normalized.flipped,
644
- colors: normalized.colors
809
+ colors: normalized.colors,
810
+ coordinates: normalized.coordinates
645
811
  });
646
812
  }
647
813
  export {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../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":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\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 type { BoardArray, BoardCell, Padding, Square } 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)$/;\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","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>>>();\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\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 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 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 { SQUARES } from \"./board\";\n\nexport interface SquareGeometry {\n x: number;\n y: number;\n size: number;\n}\n\nexport interface BoardGeometry {\n imageWidth: number;\n imageHeight: number;\n squareSize: number;\n boardX: number;\n boardY: number;\n boardSize: number;\n squares: Record<Square, SquareGeometry>;\n}\n\ninterface BoardGeometryOptions {\n size: number;\n padding: Padding;\n flipped: boolean;\n}\n\nexport function createBoardGeometry({\n size,\n padding,\n flipped,\n}: BoardGeometryOptions): BoardGeometry {\n const [top, right, bottom, left] = padding;\n const squareSize = size / 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 = left + (flipped ? 7 - fileIndex : fileIndex) * squareSize;\n const y = top + (flipped ? 7 - rankIndex : rankIndex) * squareSize;\n\n return [square, { x, y, size: squareSize }];\n }),\n ) as Record<Square, SquareGeometry>;\n\n return {\n imageWidth: left + size + right,\n imageHeight: top + size + bottom,\n squareSize,\n boardX: left,\n boardY: top,\n boardSize: size,\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 Padding,\n RenderOptions,\n ResolvedColors,\n Square,\n ThemeDefinition,\n} from \"../types/types\";\nimport { normalizeHighlights } from \"../core/highlights\";\nimport { normalizePadding, validateSize } 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_COLORS: ResolvedColors = {\n lightSquare: \"#f0d9b5\",\n darkSquare: \"#b58863\",\n highlight: \"rgba(255, 206, 0, 0.45)\",\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 normalizeRenderInputs(options: RenderOptions & { highlightSquares?: Square[] }): {\n size: number;\n padding: Padding;\n flipped: boolean;\n theme: ThemeDefinition;\n highlightSquares: Square[];\n colors: ResolvedColors;\n} {\n return {\n size: validateSize(options.size ?? DEFAULT_SIZE),\n padding: normalizePadding(options.padding ?? DEFAULT_PADDING),\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 };\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 flipped: normalized.flipped,\n colors: normalized.colors,\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 flipped: normalized.flipped,\n colors: normalized.colors,\n });\n}\n"],"mappings":"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","names":["createCanvas","createCanvas"]}
1
+ {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../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":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\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":["createCanvas","createCanvas","createCanvas","createCanvas"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chess2img",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Modern chess board image rendering for Node.js",
5
5
  "license": "MIT",
6
6
  "repository": {