@alepot55/chessboardjs 2.2.0 → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/.eslintrc.json +227 -0
  2. package/.github/instructions/copilot-instuctions.md +1671 -0
  3. package/README.md +127 -403
  4. package/assets/themes/alepot/theme.json +42 -0
  5. package/assets/themes/default/theme.json +42 -0
  6. package/chessboard.bundle.js +782 -119
  7. package/config/jest.config.js +15 -0
  8. package/config/rollup.config.js +35 -0
  9. package/dist/chessboard.cjs.js +10476 -0
  10. package/dist/chessboard.css +197 -0
  11. package/dist/chessboard.esm.js +10407 -0
  12. package/dist/chessboard.iife.js +10481 -0
  13. package/dist/chessboard.umd.js +10482 -0
  14. package/jest.config.js +2 -7
  15. package/package.json +18 -3
  16. package/rollup.config.js +2 -11
  17. package/{chessboard.move.js → src/components/Move.js} +3 -3
  18. package/src/components/Piece.js +273 -0
  19. package/{chessboard.square.js → src/components/Square.js} +60 -7
  20. package/src/constants/index.js +15 -0
  21. package/src/constants/positions.js +62 -0
  22. package/src/core/Chessboard.js +1930 -0
  23. package/src/core/ChessboardConfig.js +458 -0
  24. package/src/core/ChessboardFactory.js +385 -0
  25. package/src/core/index.js +141 -0
  26. package/src/errors/ChessboardError.js +133 -0
  27. package/src/errors/index.js +15 -0
  28. package/src/errors/messages.js +189 -0
  29. package/src/index.js +103 -0
  30. package/src/services/AnimationService.js +180 -0
  31. package/src/services/BoardService.js +156 -0
  32. package/src/services/CoordinateService.js +355 -0
  33. package/src/services/EventService.js +807 -0
  34. package/src/services/MoveService.js +594 -0
  35. package/src/services/PieceService.js +303 -0
  36. package/src/services/PositionService.js +237 -0
  37. package/src/services/ValidationService.js +673 -0
  38. package/src/services/index.js +14 -0
  39. package/src/styles/animations.css +46 -0
  40. package/{chessboard.css → src/styles/board.css} +3 -0
  41. package/src/styles/index.css +4 -0
  42. package/src/styles/pieces.css +66 -0
  43. package/src/utils/animations.js +37 -0
  44. package/{chess.js → src/utils/chess.js} +16 -16
  45. package/src/utils/coordinates.js +62 -0
  46. package/src/utils/cross-browser.js +150 -0
  47. package/src/utils/logger.js +422 -0
  48. package/src/utils/performance.js +311 -0
  49. package/src/utils/validation.js +458 -0
  50. package/tests/unit/chessboard-config-animations.test.js +106 -0
  51. package/tests/unit/chessboard-robust.test.js +163 -0
  52. package/tests/unit/chessboard.test.js +183 -0
  53. package/chessboard.config.js +0 -147
  54. package/chessboard.js +0 -981
  55. package/chessboard.piece.js +0 -115
  56. package/test/chessboard.test.js +0 -128
  57. /package/{alepot_theme → assets/themes/alepot}/bb.svg +0 -0
  58. /package/{alepot_theme → assets/themes/alepot}/bw.svg +0 -0
  59. /package/{alepot_theme → assets/themes/alepot}/kb.svg +0 -0
  60. /package/{alepot_theme → assets/themes/alepot}/kw.svg +0 -0
  61. /package/{alepot_theme → assets/themes/alepot}/nb.svg +0 -0
  62. /package/{alepot_theme → assets/themes/alepot}/nw.svg +0 -0
  63. /package/{alepot_theme → assets/themes/alepot}/pb.svg +0 -0
  64. /package/{alepot_theme → assets/themes/alepot}/pw.svg +0 -0
  65. /package/{alepot_theme → assets/themes/alepot}/qb.svg +0 -0
  66. /package/{alepot_theme → assets/themes/alepot}/qw.svg +0 -0
  67. /package/{alepot_theme → assets/themes/alepot}/rb.svg +0 -0
  68. /package/{alepot_theme → assets/themes/alepot}/rw.svg +0 -0
  69. /package/{default_pieces → assets/themes/default}/bb.svg +0 -0
  70. /package/{default_pieces → assets/themes/default}/bw.svg +0 -0
  71. /package/{default_pieces → assets/themes/default}/kb.svg +0 -0
  72. /package/{default_pieces → assets/themes/default}/kw.svg +0 -0
  73. /package/{default_pieces → assets/themes/default}/nb.svg +0 -0
  74. /package/{default_pieces → assets/themes/default}/nw.svg +0 -0
  75. /package/{default_pieces → assets/themes/default}/pb.svg +0 -0
  76. /package/{default_pieces → assets/themes/default}/pw.svg +0 -0
  77. /package/{default_pieces → assets/themes/default}/qb.svg +0 -0
  78. /package/{default_pieces → assets/themes/default}/qw.svg +0 -0
  79. /package/{default_pieces → assets/themes/default}/rb.svg +0 -0
  80. /package/{default_pieces → assets/themes/default}/rw.svg +0 -0
  81. /package/{.babelrc → config/.babelrc} +0 -0
@@ -0,0 +1,1671 @@
1
+ ---
2
+ applyTo: "**/Chessboardjs/**"
3
+ ---
4
+
5
+ # 🏗️ Chessboard.js - Guida Completa per Ingegneri Esperti
6
+
7
+ ## 📋 Panoramica del Progetto
8
+
9
+ **Chessboard.js** è un pacchetto NPM di livello enterprise per scacchiere interattive in JavaScript vanilla, progettato per massime performance, modularità e manutenibilità. Il progetto implementa pattern architetturali moderni e segue rigorosamente tutte le best practices dell'industria.
10
+
11
+ ### 🎯 Principi Architetturali
12
+
13
+ - **Separation of Concerns**: Architettura modulare con responsabilità ben definite
14
+ - **SOLID Principles**: Applicazione rigorosa dei principi di design object-oriented
15
+ - **Clean Architecture**: Dipendenze invertite e layer ben separati
16
+ - **DDD Patterns**: Domain-driven design per la logica di business
17
+ - **Performance First**: Ottimizzazioni per rendering e interazioni in tempo reale
18
+
19
+ ---
20
+
21
+ ## 🏛️ Architettura del Sistema
22
+
23
+ ### Core Architecture Layers
24
+
25
+ ```
26
+ ┌─────────────────────────────────────────────────────────────┐
27
+ │ Presentation Layer │
28
+ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│
29
+ │ │ Components │ │ Event System │ │ UI Adapters ││
30
+ │ │ - Square.js │ │ - Observers │ │ - Themes ││
31
+ │ │ - Piece.js │ │ - Handlers │ │ - Animations ││
32
+ │ │ - Move.js │ │ - Dispatchers │ │ - Renderers ││
33
+ │ └─────────────────┘ └─────────────────┘ └─────────────────┘│
34
+ └─────────────────────────────────────────────────────────────┘
35
+ ┌─────────────────────────────────────────────────────────────┐
36
+ │ Application Layer │
37
+ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│
38
+ │ │ Use Cases │ │ Controllers │ │ Services ││
39
+ │ │ - Move Logic │ │ - Game Ctrl │ │ - Asset Mgmt ││
40
+ │ │ - Validation │ │ - UI Ctrl │ │ - Theme Svc ││
41
+ │ │ - Animation │ │ - Event Ctrl │ │ - Config Svc ││
42
+ │ └─────────────────┘ └─────────────────┘ └─────────────────┘│
43
+ └─────────────────────────────────────────────────────────────┘
44
+ ┌─────────────────────────────────────────────────────────────┐
45
+ │ Domain Layer │
46
+ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│
47
+ │ │ Entities │ │ Value Objects │ │ Domain Svc ││
48
+ │ │ - Chessboard │ │ - Position │ │ - Move Engine ││
49
+ │ │ - Game State │ │ - Coordinates │ │ - Rules Eng ││
50
+ │ │ - Config │ │ - Square │ │ - Validators ││
51
+ │ └─────────────────┘ └─────────────────┘ └─────────────────┘│
52
+ └─────────────────────────────────────────────────────────────┘
53
+ ┌─────────────────────────────────────────────────────────────┐
54
+ │ Infrastructure Layer │
55
+ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│
56
+ │ │ Utilities │ │ External Deps │ │ Platform ││
57
+ │ │ - DOM Utils │ │ - Chess.js │ │ - Browser API ││
58
+ │ │ - Math Utils │ │ - Animations │ │ - Web Workers ││
59
+ │ │ - Performance │ │ - Asset Load │ │ - Storage ││
60
+ │ └─────────────────┘ └─────────────────┘ └─────────────────┘│
61
+ └─────────────────────────────────────────────────────────────┘
62
+ ```
63
+
64
+ ### 📁 Struttura Directory Ottimizzata
65
+
66
+ ```
67
+ Chessboardjs/
68
+ ├── 📁 src/ # Codice sorgente principale
69
+ │ ├── 📁 core/ # Layer del dominio
70
+ │ │ ├── 📄 Chessboard.js # Entity principale
71
+ │ │ ├── 📄 ChessboardConfig.js # Configuration management
72
+ │ │ ├── 📄 GameState.js # State management
73
+ │ │ └── 📄 index.js # Core exports
74
+ │ ├── 📁 components/ # UI Components (Presentation)
75
+ │ │ ├── 📄 Square.js # Square component
76
+ │ │ ├── 📄 Piece.js # Piece component
77
+ │ │ ├── 📄 Move.js # Move component
78
+ │ │ ├── 📄 Board.js # Board container
79
+ │ │ └── 📄 index.js # Components barrel
80
+ │ ├── 📁 services/ # Application Services
81
+ │ │ ├── 📄 AssetService.js # Asset loading/caching
82
+ │ │ ├── 📄 ThemeService.js # Theme management
83
+ │ │ ├── 📄 AnimationService.js # Animation orchestration
84
+ │ │ ├── 📄 EventService.js # Event management
85
+ │ │ └── 📄 ValidationService.js # Input validation
86
+ │ ├── 📁 controllers/ # Application Controllers
87
+ │ │ ├── 📄 GameController.js # Game logic control
88
+ │ │ ├── 📄 UIController.js # UI state control
89
+ │ │ └── 📄 EventController.js # Event coordination
90
+ │ ├── 📁 domain/ # Domain Logic
91
+ │ │ ├── 📄 MoveEngine.js # Move calculation
92
+ │ │ ├── 📄 RulesEngine.js # Chess rules
93
+ │ │ ├── 📄 PositionValidator.js # Position validation
94
+ │ │ └── 📄 GameRules.js # Game rule definitions
95
+ │ ├── 📁 value-objects/ # Value Objects
96
+ │ │ ├── 📄 Position.js # Board position
97
+ │ │ ├── 📄 Coordinates.js # Square coordinates
98
+ │ │ ├── 📄 Move.js # Move representation
99
+ │ │ └── 📄 Color.js # Color value object
100
+ │ ├── 📁 utils/ # Infrastructure Utilities
101
+ │ │ ├── 📄 dom.js # DOM manipulation
102
+ │ │ ├── 📄 animations.js # Animation helpers
103
+ │ │ ├── 📄 coordinates.js # Coordinate calculations
104
+ │ │ ├── 📄 performance.js # Performance monitoring
105
+ │ │ ├── 📄 validation.js # Input validation
106
+ │ │ ├── 📄 debounce.js # Debouncing utilities
107
+ │ │ └── 📄 logger.js # Logging system
108
+ │ ├── 📁 styles/ # CSS Modules
109
+ │ │ ├── 📄 index.css # Main stylesheet
110
+ │ │ ├── 📄 board.css # Board styling
111
+ │ │ ├── 📄 pieces.css # Piece styling
112
+ │ │ ├── 📄 animations.css # Animation definitions
113
+ │ │ ├── 📄 themes.css # Theme variables
114
+ │ │ └── 📄 responsive.css # Responsive design
115
+ │ ├── 📁 types/ # Type definitions
116
+ │ │ ├── 📄 index.d.ts # Main type exports
117
+ │ │ ├── 📄 chessboard.d.ts # Chessboard types
118
+ │ │ ├── 📄 config.d.ts # Configuration types
119
+ │ │ └── 📄 events.d.ts # Event types
120
+ │ └── 📄 index.js # Main entry point
121
+ ├── 📁 assets/ # Static Assets
122
+ │ ├── 📁 themes/ # Tema collections
123
+ │ │ ├── 📁 default/ # Default theme
124
+ │ │ │ ├── 📄 theme.json # Theme metadata
125
+ │ │ │ └── 📁 pieces/ # Piece assets
126
+ │ │ ├── 📁 alepot/ # Custom theme
127
+ │ │ └── 📁 [theme-name]/ # Additional themes
128
+ │ ├── 📁 pieces/ # Universal piece sets
129
+ │ │ ├── 📁 svg/ # SVG pieces (preferred)
130
+ │ │ ├── 📁 png/ # PNG fallbacks
131
+ │ │ └── 📁 webp/ # WebP optimized
132
+ │ └── 📁 sounds/ # Audio assets
133
+ ├── 📁 dist/ # Build Output
134
+ │ ├── 📄 chessboard.esm.js # ES Modules
135
+ │ ├── 📄 chessboard.cjs.js # CommonJS
136
+ │ ├── 📄 chessboard.umd.js # UMD
137
+ │ ├── 📄 chessboard.iife.js # IIFE (browsers)
138
+ │ ├── 📄 chessboard.min.js # Minified version
139
+ │ ├── 📄 chessboard.css # Compiled CSS
140
+ │ └── 📁 types/ # TypeScript declarations
141
+ ├── 📁 tests/ # Test Suites
142
+ │ ├── 📁 unit/ # Unit tests
143
+ │ │ ├── 📁 core/ # Core logic tests
144
+ │ │ ├── 📁 components/ # Component tests
145
+ │ │ ├── 📁 services/ # Service tests
146
+ │ │ └── 📁 utils/ # Utility tests
147
+ │ ├── 📁 integration/ # Integration tests
148
+ │ │ ├── 📄 game-flow.test.js # Game flow tests
149
+ │ │ ├── 📄 ui-interaction.test.js # UI interaction tests
150
+ │ │ └── 📄 api-integration.test.js # API integration tests
151
+ │ ├── 📁 e2e/ # End-to-end tests
152
+ │ │ ├── 📄 user-scenarios.test.js # User journey tests
153
+ │ │ ├── 📄 performance.test.js # Performance tests
154
+ │ │ └── 📄 accessibility.test.js # A11y tests
155
+ │ ├── 📁 fixtures/ # Test data
156
+ │ │ ├── 📄 positions.json # Sample positions
157
+ │ │ ├── 📄 games.pgn # Sample games
158
+ │ │ └── 📄 configs.json # Test configurations
159
+ │ └── 📁 helpers/ # Test utilities
160
+ ├── 📁 docs/ # Documentation
161
+ │ ├── 📄 README.md # Project overview
162
+ │ ├── 📄 API.md # Complete API reference
163
+ │ ├── 📄 ARCHITECTURE.md # Architecture guide
164
+ │ ├── 📄 CONTRIBUTING.md # Contribution guidelines
165
+ │ ├── 📄 PERFORMANCE.md # Performance guide
166
+ │ ├── 📁 api/ # Generated API docs
167
+ │ ├── 📁 examples/ # Usage examples
168
+ │ │ ├── 📄 basic-usage.html # Basic setup
169
+ │ │ ├── 📄 advanced-config.html # Advanced configuration
170
+ │ │ ├── 📄 custom-themes.html # Custom theming
171
+ │ │ ├── 📄 game-integration.html # Chess.js integration
172
+ │ │ └── 📄 performance-demo.html # Performance showcase
173
+ │ └── 📁 guides/ # Development guides
174
+ │ ├── 📄 getting-started.md # Quick start guide
175
+ │ ├── 📄 customization.md # Customization guide
176
+ │ ├── 📄 theming.md # Theming guide
177
+ │ ├── 📄 performance.md # Performance optimization
178
+ │ └── 📄 troubleshooting.md # Common issues
179
+ ├── 📁 tools/ # Development Tools
180
+ │ ├── 📄 build.js # Build orchestration
181
+ │ ├── 📄 dev-server.js # Development server
182
+ │ ├── 📄 theme-validator.js # Theme validation
183
+ │ ├── 📄 performance-monitor.js # Performance monitoring
184
+ │ └── 📄 asset-optimizer.js # Asset optimization
185
+ ├── 📁 config/ # Configuration Files
186
+ │ ├── 📄 rollup.config.js # Rollup configuration
187
+ │ ├── 📄 jest.config.js # Jest configuration
188
+ │ ├── 📄 eslint.config.js # ESLint rules
189
+ │ ├── 📄 prettier.config.js # Prettier formatting
190
+ │ ├── 📄 babel.config.js # Babel configuration
191
+ │ └── 📄 typescript.config.json # TypeScript configuration
192
+ ├── 📁 benchmarks/ # Performance Benchmarks
193
+ │ ├── 📄 rendering-bench.js # Rendering performance
194
+ │ ├── 📄 animation-bench.js # Animation performance
195
+ │ └── 📄 memory-bench.js # Memory usage tests
196
+ └── 📁 scripts/ # Automation Scripts
197
+ ├── 📄 release.js # Release automation
198
+ ├── 📄 version-bump.js # Version management
199
+ ├── 📄 changelog-gen.js # Changelog generation
200
+ └── 📄 deploy.js # Deployment automation
201
+ ```
202
+
203
+ ---
204
+
205
+ ## 🔧 Configurazione Ambiente di Sviluppo
206
+
207
+ ### Prerequisiti Tecnici
208
+
209
+ ```json
210
+ {
211
+ "engines": {
212
+ "node": ">=18.0.0",
213
+ "npm": ">=9.0.0"
214
+ },
215
+ "browserslist": [
216
+ "> 1%",
217
+ "last 2 versions",
218
+ "not dead",
219
+ "not ie 11"
220
+ ]
221
+ }
222
+ ```
223
+
224
+ ### Dipendenze di Sviluppo Raccomandate
225
+
226
+ ```json
227
+ {
228
+ "devDependencies": {
229
+ // Build & Bundling
230
+ "rollup": "^4.0.0",
231
+ "@rollup/plugin-node-resolve": "^15.0.0",
232
+ "@rollup/plugin-commonjs": "^25.0.0",
233
+ "@rollup/plugin-terser": "^0.4.0",
234
+ "@rollup/plugin-babel": "^6.0.0",
235
+ "rollup-plugin-postcss": "^4.0.0",
236
+ "rollup-plugin-analyzer": "^4.0.0",
237
+
238
+ // TypeScript Support
239
+ "typescript": "^5.0.0",
240
+ "@rollup/plugin-typescript": "^11.0.0",
241
+ "tslib": "^2.5.0",
242
+
243
+ // Testing Framework
244
+ "jest": "^29.0.0",
245
+ "jest-environment-jsdom": "^29.0.0",
246
+ "@testing-library/jest-dom": "^6.0.0",
247
+ "@testing-library/dom": "^9.0.0",
248
+ "jest-performance": "^1.0.0",
249
+
250
+ // E2E Testing
251
+ "playwright": "^1.40.0",
252
+ "@playwright/test": "^1.40.0",
253
+
254
+ // Code Quality
255
+ "eslint": "^8.50.0",
256
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
257
+ "@typescript-eslint/parser": "^6.0.0",
258
+ "eslint-config-prettier": "^9.0.0",
259
+ "eslint-plugin-import": "^2.28.0",
260
+ "eslint-plugin-jest": "^27.0.0",
261
+ "prettier": "^3.0.0",
262
+
263
+ // CSS Processing
264
+ "postcss": "^8.4.0",
265
+ "autoprefixer": "^10.4.0",
266
+ "cssnano": "^6.0.0",
267
+ "postcss-custom-properties": "^13.0.0",
268
+
269
+ // Documentation
270
+ "jsdoc": "^4.0.0",
271
+ "typedoc": "^0.25.0",
272
+ "docsify-cli": "^4.4.0",
273
+
274
+ // Performance & Monitoring
275
+ "lighthouse": "^11.0.0",
276
+ "bundlesize": "^0.18.0",
277
+ "size-limit": "^9.0.0",
278
+
279
+ // Automation
280
+ "husky": "^8.0.0",
281
+ "lint-staged": "^14.0.0",
282
+ "commitizen": "^4.3.0",
283
+ "semantic-release": "^21.0.0"
284
+ }
285
+ }
286
+ ```
287
+
288
+ ### Script NPM Ottimizzati
289
+
290
+ ```json
291
+ {
292
+ "scripts": {
293
+ // Development
294
+ "dev": "rollup -c config/rollup.config.js --watch --environment NODE_ENV:development",
295
+ "dev:debug": "rollup -c config/rollup.config.js --watch --environment NODE_ENV:development,DEBUG:true",
296
+ "dev:server": "node tools/dev-server.js",
297
+
298
+ // Building
299
+ "build": "npm run clean && npm run build:lib && npm run build:types && npm run build:css",
300
+ "build:lib": "rollup -c config/rollup.config.js --environment NODE_ENV:production",
301
+ "build:types": "tsc --emitDeclarationOnly",
302
+ "build:css": "postcss src/styles/index.css -o dist/chessboard.css",
303
+ "build:analyze": "npm run build && rollup-plugin-analyzer",
304
+
305
+ // Testing
306
+ "test": "jest --config config/jest.config.js",
307
+ "test:watch": "jest --config config/jest.config.js --watch",
308
+ "test:coverage": "jest --config config/jest.config.js --coverage",
309
+ "test:unit": "jest --config config/jest.config.js tests/unit",
310
+ "test:integration": "jest --config config/jest.config.js tests/integration",
311
+ "test:e2e": "playwright test",
312
+ "test:performance": "node benchmarks/performance-suite.js",
313
+
314
+ // Code Quality
315
+ "lint": "eslint src/ tests/ --ext .js,.ts",
316
+ "lint:fix": "eslint src/ tests/ --ext .js,.ts --fix",
317
+ "format": "prettier --write \"src/**/*.{js,ts,css}\" \"tests/**/*.{js,ts}\"",
318
+ "typecheck": "tsc --noEmit",
319
+
320
+ // Documentation
321
+ "docs:build": "jsdoc src/ -c config/jsdoc.config.json -d docs/api",
322
+ "docs:serve": "docsify serve docs",
323
+ "docs:types": "typedoc src/ --out docs/types",
324
+
325
+ // Quality Assurance
326
+ "validate": "npm run lint && npm run typecheck && npm run test",
327
+ "validate:ci": "npm run validate && npm run build && npm run test:e2e",
328
+ "size-check": "size-limit",
329
+ "perf-audit": "lighthouse --config-path=config/lighthouse.config.js",
330
+
331
+ // Maintenance
332
+ "clean": "rimraf dist/ coverage/ .nyc_output/",
333
+ "clean:all": "npm run clean && rimraf node_modules/ package-lock.json",
334
+ "deps:check": "ncu --interactive --format group",
335
+ "deps:update": "ncu -u && npm install",
336
+
337
+ // Release
338
+ "version:patch": "npm version patch",
339
+ "version:minor": "npm version minor",
340
+ "version:major": "npm version major",
341
+ "prepublishOnly": "npm run validate:ci",
342
+ "release": "semantic-release",
343
+
344
+ // Git Hooks
345
+ "prepare": "husky install",
346
+ "pre-commit": "lint-staged",
347
+ "commit": "git-cz"
348
+ }
349
+ }
350
+ ```
351
+
352
+ ---
353
+
354
+ ## 🏗️ Patterns Architetturali Implementati
355
+
356
+ ### 1. Observer Pattern per Eventi
357
+
358
+ ```javascript
359
+ // src/services/EventService.js
360
+ export class EventService {
361
+ constructor() {
362
+ this.observers = new Map();
363
+ this.eventQueue = [];
364
+ this.isProcessing = false;
365
+ }
366
+
367
+ subscribe(eventType, callback, priority = 0) {
368
+ if (!this.observers.has(eventType)) {
369
+ this.observers.set(eventType, []);
370
+ }
371
+
372
+ const observer = { callback, priority, id: crypto.randomUUID() };
373
+ this.observers.get(eventType).push(observer);
374
+
375
+ // Sort by priority (higher first)
376
+ this.observers.get(eventType).sort((a, b) => b.priority - a.priority);
377
+
378
+ return observer.id;
379
+ }
380
+
381
+ async emit(eventType, data) {
382
+ const event = {
383
+ type: eventType,
384
+ data,
385
+ timestamp: Date.now(),
386
+ id: crypto.randomUUID()
387
+ };
388
+
389
+ this.eventQueue.push(event);
390
+
391
+ if (!this.isProcessing) {
392
+ await this.processQueue();
393
+ }
394
+ }
395
+
396
+ async processQueue() {
397
+ this.isProcessing = true;
398
+
399
+ while (this.eventQueue.length > 0) {
400
+ const event = this.eventQueue.shift();
401
+ await this.processEvent(event);
402
+ }
403
+
404
+ this.isProcessing = false;
405
+ }
406
+ }
407
+ ```
408
+
409
+ ### 2. Strategy Pattern per Animazioni
410
+
411
+ ```javascript
412
+ // src/services/AnimationService.js
413
+ export class AnimationService {
414
+ constructor() {
415
+ this.strategies = new Map();
416
+ this.activeAnimations = new Map();
417
+ this.setupDefaultStrategies();
418
+ }
419
+
420
+ setupDefaultStrategies() {
421
+ this.registerStrategy('ease', new EaseAnimationStrategy());
422
+ this.registerStrategy('linear', new LinearAnimationStrategy());
423
+ this.registerStrategy('bounce', new BounceAnimationStrategy());
424
+ this.registerStrategy('elastic', new ElasticAnimationStrategy());
425
+ }
426
+
427
+ registerStrategy(name, strategy) {
428
+ this.strategies.set(name, strategy);
429
+ }
430
+
431
+ async animate(element, properties, options = {}) {
432
+ const strategy = this.strategies.get(options.easing || 'ease');
433
+
434
+ if (!strategy) {
435
+ throw new Error(`Animation strategy '${options.easing}' not found`);
436
+ }
437
+
438
+ const animation = await strategy.animate(element, properties, options);
439
+ this.activeAnimations.set(animation.id, animation);
440
+
441
+ animation.finished.then(() => {
442
+ this.activeAnimations.delete(animation.id);
443
+ });
444
+
445
+ return animation;
446
+ }
447
+ }
448
+ ```
449
+
450
+ ### 3. Factory Pattern per Componenti
451
+
452
+ ```javascript
453
+ // src/components/ComponentFactory.js
454
+ export class ComponentFactory {
455
+ constructor(services) {
456
+ this.services = services;
457
+ this.componentRegistry = new Map();
458
+ this.registerDefaults();
459
+ }
460
+
461
+ registerDefaults() {
462
+ this.register('square', SquareComponent);
463
+ this.register('piece', PieceComponent);
464
+ this.register('move', MoveComponent);
465
+ this.register('board', BoardComponent);
466
+ }
467
+
468
+ register(type, ComponentClass) {
469
+ this.componentRegistry.set(type, ComponentClass);
470
+ }
471
+
472
+ create(type, config = {}) {
473
+ const ComponentClass = this.componentRegistry.get(type);
474
+
475
+ if (!ComponentClass) {
476
+ throw new Error(`Component type '${type}' not registered`);
477
+ }
478
+
479
+ return new ComponentClass({
480
+ ...config,
481
+ services: this.services
482
+ });
483
+ }
484
+
485
+ createBoard(config) {
486
+ const board = this.create('board', config);
487
+
488
+ // Create 64 squares
489
+ for (let rank = 0; rank < 8; rank++) {
490
+ for (let file = 0; file < 8; file++) {
491
+ const square = this.create('square', {
492
+ rank,
493
+ file,
494
+ color: (rank + file) % 2 === 0 ? 'light' : 'dark'
495
+ });
496
+ board.addSquare(square);
497
+ }
498
+ }
499
+
500
+ return board;
501
+ }
502
+ }
503
+ ```
504
+
505
+ ### 4. Command Pattern per Azioni
506
+
507
+ ```javascript
508
+ // src/domain/commands/MoveCommand.js
509
+ export class MoveCommand {
510
+ constructor(from, to, piece, capturedPiece = null) {
511
+ this.from = from;
512
+ this.to = to;
513
+ this.piece = piece;
514
+ this.capturedPiece = capturedPiece;
515
+ this.timestamp = Date.now();
516
+ this.id = crypto.randomUUID();
517
+ }
518
+
519
+ execute(board) {
520
+ // Store previous state for undo
521
+ this.previousState = board.getState();
522
+
523
+ // Execute the move
524
+ board.movePiece(this.from, this.to);
525
+
526
+ if (this.capturedPiece) {
527
+ board.removePiece(this.to);
528
+ }
529
+
530
+ // Emit move event
531
+ board.emit('move', {
532
+ command: this,
533
+ from: this.from,
534
+ to: this.to,
535
+ piece: this.piece
536
+ });
537
+ }
538
+
539
+ undo(board) {
540
+ if (!this.previousState) {
541
+ throw new Error('Cannot undo command that was never executed');
542
+ }
543
+
544
+ board.setState(this.previousState);
545
+
546
+ board.emit('move-undone', {
547
+ command: this,
548
+ restoredState: this.previousState
549
+ });
550
+ }
551
+
552
+ canExecute(board) {
553
+ return board.isValidMove(this.from, this.to);
554
+ }
555
+ }
556
+ ```
557
+
558
+ ---
559
+
560
+ ## 🎯 Best Practices di Sviluppo
561
+
562
+ ### Convenzioni di Codice
563
+
564
+ #### 1. Naming Conventions
565
+
566
+ ```javascript
567
+ // Classes: PascalCase
568
+ class ChessboardController { }
569
+ class MoveValidationService { }
570
+
571
+ // Methods e Variables: camelCase
572
+ const currentPosition = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR';
573
+ function validateMoveInput(from, to) { }
574
+
575
+ // Constants: UPPER_SNAKE_CASE
576
+ const DEFAULT_ANIMATION_DURATION = 200;
577
+ const PIECE_TYPES = ['p', 'r', 'n', 'b', 'q', 'k'];
578
+
579
+ // Private methods: underscore prefix
580
+ class Chessboard {
581
+ _initializeBoard() { }
582
+ _setupEventListeners() { }
583
+ }
584
+
585
+ // Files: PascalCase for classes, camelCase for utilities
586
+ // ChessboardController.js
587
+ // animationHelpers.js
588
+ ```
589
+
590
+ #### 2. Struttura Metodi
591
+
592
+ ```javascript
593
+ class ComponentBase {
594
+ /**
595
+ * Public method template
596
+ */
597
+ async publicMethod(param1, param2, options = {}) {
598
+ // 1. Input validation
599
+ this._validateInputs(param1, param2, options);
600
+
601
+ // 2. Pre-processing
602
+ const normalizedOptions = this._normalizeOptions(options);
603
+
604
+ try {
605
+ // 3. Core logic
606
+ const result = await this._executeOperation(param1, param2, normalizedOptions);
607
+
608
+ // 4. Post-processing
609
+ return this._formatResult(result);
610
+
611
+ } catch (error) {
612
+ // 5. Error handling
613
+ this._handleError(error, { param1, param2, options });
614
+ throw error;
615
+ }
616
+ }
617
+
618
+ /**
619
+ * Private validation method
620
+ */
621
+ _validateInputs(param1, param2, options) {
622
+ if (!param1) {
623
+ throw new ValidationError('param1 is required');
624
+ }
625
+
626
+ if (typeof param2 !== 'string') {
627
+ throw new ValidationError('param2 must be a string');
628
+ }
629
+ }
630
+ }
631
+ ```
632
+
633
+ #### 3. Error Handling Strategy
634
+
635
+ ```javascript
636
+ // src/utils/errors.js
637
+ export class ChessboardError extends Error {
638
+ constructor(message, code, context = {}) {
639
+ super(message);
640
+ this.name = 'ChessboardError';
641
+ this.code = code;
642
+ this.context = context;
643
+ this.timestamp = new Date().toISOString();
644
+ }
645
+ }
646
+
647
+ export class ValidationError extends ChessboardError {
648
+ constructor(message, field, value) {
649
+ super(message, 'VALIDATION_ERROR', { field, value });
650
+ this.name = 'ValidationError';
651
+ }
652
+ }
653
+
654
+ export class ConfigurationError extends ChessboardError {
655
+ constructor(message, configKey, configValue) {
656
+ super(message, 'CONFIG_ERROR', { configKey, configValue });
657
+ this.name = 'ConfigurationError';
658
+ }
659
+ }
660
+
661
+ // Usage in components
662
+ class ChessboardConfig {
663
+ validate() {
664
+ if (!this.id) {
665
+ throw new ValidationError(
666
+ 'Chessboard ID is required',
667
+ 'id',
668
+ this.id
669
+ );
670
+ }
671
+
672
+ if (!['w', 'b'].includes(this.orientation)) {
673
+ throw new ConfigurationError(
674
+ 'Invalid orientation value',
675
+ 'orientation',
676
+ this.orientation
677
+ );
678
+ }
679
+ }
680
+ }
681
+ ```
682
+
683
+ ### Performance Optimization
684
+
685
+ #### 1. Lazy Loading e Code Splitting
686
+
687
+ ```javascript
688
+ // src/services/AssetService.js
689
+ export class AssetService {
690
+ constructor() {
691
+ this.cache = new Map();
692
+ this.loadingPromises = new Map();
693
+ this.preloadQueue = [];
694
+ }
695
+
696
+ async loadTheme(themeName) {
697
+ if (this.cache.has(themeName)) {
698
+ return this.cache.get(themeName);
699
+ }
700
+
701
+ if (this.loadingPromises.has(themeName)) {
702
+ return this.loadingPromises.get(themeName);
703
+ }
704
+
705
+ const promise = this._loadThemeData(themeName);
706
+ this.loadingPromises.set(themeName, promise);
707
+
708
+ try {
709
+ const theme = await promise;
710
+ this.cache.set(themeName, theme);
711
+ return theme;
712
+ } finally {
713
+ this.loadingPromises.delete(themeName);
714
+ }
715
+ }
716
+
717
+ async _loadThemeData(themeName) {
718
+ // Dynamic import for code splitting
719
+ const { default: themeModule } = await import(`../assets/themes/${themeName}/theme.js`);
720
+
721
+ // Parallel loading of assets
722
+ const [pieces, metadata] = await Promise.all([
723
+ this._loadPieces(themeName),
724
+ this._loadThemeMetadata(themeName)
725
+ ]);
726
+
727
+ return {
728
+ ...themeModule,
729
+ pieces,
730
+ metadata
731
+ };
732
+ }
733
+ }
734
+ ```
735
+
736
+ #### 2. Memory Management
737
+
738
+ ```javascript
739
+ // src/core/Chessboard.js
740
+ export class Chessboard {
741
+ constructor(config) {
742
+ this.eventListeners = new Set();
743
+ this.animationFrames = new Set();
744
+ this.timers = new Set();
745
+ this.observers = new Set();
746
+
747
+ // WeakMap for DOM associations
748
+ this.elementData = new WeakMap();
749
+ }
750
+
751
+ destroy() {
752
+ // Clean up event listeners
753
+ this.eventListeners.forEach(listener => {
754
+ listener.element.removeEventListener(listener.event, listener.handler);
755
+ });
756
+ this.eventListeners.clear();
757
+
758
+ // Cancel animations
759
+ this.animationFrames.forEach(frameId => {
760
+ cancelAnimationFrame(frameId);
761
+ });
762
+ this.animationFrames.clear();
763
+
764
+ // Clear timers
765
+ this.timers.forEach(timerId => {
766
+ clearTimeout(timerId);
767
+ });
768
+ this.timers.clear();
769
+
770
+ // Disconnect observers
771
+ this.observers.forEach(observer => {
772
+ observer.disconnect();
773
+ });
774
+ this.observers.clear();
775
+
776
+ // Clear DOM references
777
+ this.element = null;
778
+ this.squares = null;
779
+ this.pieces = null;
780
+ }
781
+ }
782
+ ```
783
+
784
+ #### 3. Rendering Optimization
785
+
786
+ ```javascript
787
+ // src/utils/rendering.js
788
+ export class RenderOptimizer {
789
+ constructor() {
790
+ this.pendingUpdates = new Map();
791
+ this.updateScheduled = false;
792
+ }
793
+
794
+ scheduleUpdate(element, updateFn) {
795
+ this.pendingUpdates.set(element, updateFn);
796
+
797
+ if (!this.updateScheduled) {
798
+ this.updateScheduled = true;
799
+ requestAnimationFrame(() => this.flushUpdates());
800
+ }
801
+ }
802
+
803
+ flushUpdates() {
804
+ // Batch DOM reads first
805
+ const measurements = new Map();
806
+ for (const [element] of this.pendingUpdates) {
807
+ measurements.set(element, {
808
+ rect: element.getBoundingClientRect(),
809
+ computedStyle: getComputedStyle(element)
810
+ });
811
+ }
812
+
813
+ // Then batch DOM writes
814
+ for (const [element, updateFn] of this.pendingUpdates) {
815
+ const measurement = measurements.get(element);
816
+ updateFn(element, measurement);
817
+ }
818
+
819
+ this.pendingUpdates.clear();
820
+ this.updateScheduled = false;
821
+ }
822
+ }
823
+ ```
824
+
825
+ ---
826
+
827
+ ## 🧪 Testing Strategy Completa
828
+
829
+ ### 1. Unit Testing (Jest)
830
+
831
+ ```javascript
832
+ // tests/unit/core/Chessboard.test.js
833
+ import { Chessboard } from '../../../src/core/Chessboard.js';
834
+ import { ValidationError } from '../../../src/utils/errors.js';
835
+
836
+ describe('Chessboard Core', () => {
837
+ let chessboard;
838
+ let mockContainer;
839
+
840
+ beforeEach(() => {
841
+ mockContainer = document.createElement('div');
842
+ mockContainer.id = 'test-board';
843
+ document.body.appendChild(mockContainer);
844
+
845
+ chessboard = new Chessboard({
846
+ id: 'test-board',
847
+ position: 'start'
848
+ });
849
+ });
850
+
851
+ afterEach(() => {
852
+ chessboard?.destroy();
853
+ document.body.removeChild(mockContainer);
854
+ });
855
+
856
+ describe('Initialization', () => {
857
+ it('should create chessboard with valid config', () => {
858
+ expect(chessboard).toBeInstanceOf(Chessboard);
859
+ expect(chessboard.element).toBe(mockContainer);
860
+ });
861
+
862
+ it('should throw ValidationError for invalid config', () => {
863
+ expect(() => {
864
+ new Chessboard({ id: null });
865
+ }).toThrow(ValidationError);
866
+ });
867
+ });
868
+
869
+ describe('Move Handling', () => {
870
+ it('should execute valid move', async () => {
871
+ const moveResult = await chessboard.move('e2', 'e4');
872
+
873
+ expect(moveResult.success).toBe(true);
874
+ expect(chessboard.get('e4')).toBe('pw');
875
+ expect(chessboard.get('e2')).toBe(null);
876
+ });
877
+
878
+ it('should reject invalid move', async () => {
879
+ const moveResult = await chessboard.move('e2', 'e5');
880
+
881
+ expect(moveResult.success).toBe(false);
882
+ expect(moveResult.error).toBeDefined();
883
+ });
884
+ });
885
+ });
886
+ ```
887
+
888
+ ### 2. Integration Testing
889
+
890
+ ```javascript
891
+ // tests/integration/game-flow.test.js
892
+ import { Chessboard } from '../../src/core/Chessboard.js';
893
+ import { Chess } from 'chess.js';
894
+
895
+ describe('Game Flow Integration', () => {
896
+ let board;
897
+ let chess;
898
+
899
+ beforeEach(() => {
900
+ const container = document.createElement('div');
901
+ container.id = 'integration-test';
902
+ document.body.appendChild(container);
903
+
904
+ chess = new Chess();
905
+ board = new Chessboard({
906
+ id: 'integration-test',
907
+ position: chess.fen(),
908
+ onMove: (move) => {
909
+ const result = chess.move(move);
910
+ if (result) {
911
+ board.position(chess.fen());
912
+ return true;
913
+ }
914
+ return false;
915
+ }
916
+ });
917
+ });
918
+
919
+ it('should play complete game with chess.js integration', async () => {
920
+ const moves = [
921
+ ['e2', 'e4'], ['e7', 'e5'],
922
+ ['g1', 'f3'], ['b8', 'c6'],
923
+ ['f1', 'c4'], ['f8', 'c5']
924
+ ];
925
+
926
+ for (const [from, to] of moves) {
927
+ const result = await board.move(from, to);
928
+ expect(result.success).toBe(true);
929
+ }
930
+
931
+ expect(chess.history().length).toBe(6);
932
+ expect(board.fen()).toBe(chess.fen());
933
+ });
934
+ });
935
+ ```
936
+
937
+ ### 3. E2E Testing (Playwright)
938
+
939
+ ```javascript
940
+ // tests/e2e/user-interaction.spec.js
941
+ import { test, expect } from '@playwright/test';
942
+
943
+ test.describe('Chessboard User Interactions', () => {
944
+ test.beforeEach(async ({ page }) => {
945
+ await page.goto('/examples/basic-usage.html');
946
+ await page.waitForSelector('#chessboard');
947
+ });
948
+
949
+ test('should allow drag and drop moves', async ({ page }) => {
950
+ const board = page.locator('#chessboard');
951
+
952
+ // Drag white pawn from e2 to e4
953
+ await page.dragAndDrop(
954
+ '[data-square="e2"] .piece',
955
+ '[data-square="e4"]'
956
+ );
957
+
958
+ // Verify move was executed
959
+ await expect(page.locator('[data-square="e4"] .piece')).toBeVisible();
960
+ await expect(page.locator('[data-square="e2"] .piece')).not.toBeVisible();
961
+ });
962
+
963
+ test('should show legal move hints', async ({ page }) => {
964
+ // Click on knight
965
+ await page.click('[data-square="g1"] .piece');
966
+
967
+ // Check that legal move squares are highlighted
968
+ await expect(page.locator('[data-square="f3"].hint')).toBeVisible();
969
+ await expect(page.locator('[data-square="h3"].hint')).toBeVisible();
970
+ });
971
+
972
+ test('should handle invalid moves gracefully', async ({ page }) => {
973
+ // Try to move pawn backwards
974
+ await page.dragAndDrop(
975
+ '[data-square="e2"] .piece',
976
+ '[data-square="e1"]'
977
+ );
978
+
979
+ // Piece should return to original position
980
+ await expect(page.locator('[data-square="e2"] .piece')).toBeVisible();
981
+ await expect(page.locator('[data-square="e1"] .piece')).not.toBeVisible();
982
+ });
983
+ });
984
+ ```
985
+
986
+ ### 4. Performance Testing
987
+
988
+ ```javascript
989
+ // benchmarks/rendering-performance.js
990
+ import { performance } from 'perf_hooks';
991
+ import { Chessboard } from '../src/core/Chessboard.js';
992
+
993
+ class PerformanceBenchmark {
994
+ async runRenderingBenchmark() {
995
+ const iterations = 1000;
996
+ const times = [];
997
+
998
+ for (let i = 0; i < iterations; i++) {
999
+ const start = performance.now();
1000
+
1001
+ const board = new Chessboard({
1002
+ id: 'benchmark-board',
1003
+ position: 'start',
1004
+ size: 400
1005
+ });
1006
+
1007
+ await board.build();
1008
+
1009
+ const end = performance.now();
1010
+ times.push(end - start);
1011
+
1012
+ board.destroy();
1013
+ }
1014
+
1015
+ return {
1016
+ mean: times.reduce((a, b) => a + b) / times.length,
1017
+ min: Math.min(...times),
1018
+ max: Math.max(...times),
1019
+ p95: this.percentile(times, 95),
1020
+ p99: this.percentile(times, 99)
1021
+ };
1022
+ }
1023
+
1024
+ percentile(arr, p) {
1025
+ const sorted = arr.sort((a, b) => a - b);
1026
+ const index = (p / 100) * (sorted.length - 1);
1027
+ return sorted[Math.round(index)];
1028
+ }
1029
+ }
1030
+ ```
1031
+
1032
+ ---
1033
+
1034
+ ## 📚 Sistema di Documentazione
1035
+
1036
+ ### 1. JSDoc Standards
1037
+
1038
+ ```javascript
1039
+ /**
1040
+ * Represents a chess piece on the board
1041
+ * @class
1042
+ * @memberof Components
1043
+ * @since 2.0.0
1044
+ *
1045
+ * @example
1046
+ * const piece = new Piece({
1047
+ * type: 'pawn',
1048
+ * color: 'white',
1049
+ * square: 'e2'
1050
+ * });
1051
+ */
1052
+ export class Piece {
1053
+ /**
1054
+ * Creates a new chess piece
1055
+ * @param {Object} config - Piece configuration
1056
+ * @param {string} config.type - Piece type (pawn, rook, knight, bishop, queen, king)
1057
+ * @param {string} config.color - Piece color (white, black)
1058
+ * @param {string} config.square - Current square position
1059
+ * @param {Object} [config.element] - DOM element for the piece
1060
+ * @throws {ValidationError} When configuration is invalid
1061
+ *
1062
+ * @example
1063
+ * const piece = new Piece({
1064
+ * type: 'queen',
1065
+ * color: 'black',
1066
+ * square: 'd8'
1067
+ * });
1068
+ */
1069
+ constructor(config) {
1070
+ this._validateConfig(config);
1071
+
1072
+ /**
1073
+ * Piece type
1074
+ * @type {string}
1075
+ * @readonly
1076
+ */
1077
+ this.type = config.type;
1078
+
1079
+ /**
1080
+ * Piece color
1081
+ * @type {string}
1082
+ * @readonly
1083
+ */
1084
+ this.color = config.color;
1085
+
1086
+ /**
1087
+ * Current square position
1088
+ * @type {string}
1089
+ * @private
1090
+ */
1091
+ this._square = config.square;
1092
+ }
1093
+
1094
+ /**
1095
+ * Moves the piece to a new square
1096
+ * @param {string} targetSquare - Target square notation (e.g., 'e4')
1097
+ * @param {Object} [options={}] - Move options
1098
+ * @param {boolean} [options.animate=true] - Whether to animate the move
1099
+ * @param {number} [options.duration=200] - Animation duration in milliseconds
1100
+ * @returns {Promise<boolean>} True if move was successful
1101
+ *
1102
+ * @example
1103
+ * await piece.moveTo('e4', { animate: true, duration: 300 });
1104
+ */
1105
+ async moveTo(targetSquare, options = {}) {
1106
+ // Implementation...
1107
+ }
1108
+ }
1109
+ ```
1110
+
1111
+ ### 2. TypeScript Definitions
1112
+
1113
+ ```typescript
1114
+ // src/types/chessboard.d.ts
1115
+ export interface ChessboardConfig {
1116
+ /** HTML element ID where the board will be rendered */
1117
+ id: string;
1118
+
1119
+ /** Board position as FEN string or predefined position */
1120
+ position?: string | 'start' | 'empty';
1121
+
1122
+ /** Board orientation */
1123
+ orientation?: 'white' | 'black' | 'w' | 'b';
1124
+
1125
+ /** Board size in pixels or 'auto' */
1126
+ size?: number | 'auto';
1127
+
1128
+ /** Enable drag and drop */
1129
+ draggable?: boolean;
1130
+
1131
+ /** Show legal move hints */
1132
+ hints?: boolean;
1133
+
1134
+ /** Enable click-to-move */
1135
+ clickable?: boolean;
1136
+
1137
+ /** Colors allowed to move */
1138
+ movableColors?: 'white' | 'black' | 'both' | 'none';
1139
+
1140
+ /** Highlight last move */
1141
+ moveHighlight?: boolean;
1142
+
1143
+ /** Animation easing function */
1144
+ moveAnimation?: AnimationEasing;
1145
+
1146
+ /** Animation duration */
1147
+ moveTime?: AnimationDuration | number;
1148
+
1149
+ /** What happens when piece is dropped off board */
1150
+ dropOffBoard?: 'snapback' | 'trash';
1151
+
1152
+ /** Only allow legal moves */
1153
+ onlyLegalMoves?: boolean;
1154
+
1155
+ /** Piece theme configuration */
1156
+ pieceTheme?: string | PieceThemeFunction;
1157
+
1158
+ /** Board color scheme */
1159
+ whiteSquare?: string;
1160
+ blackSquare?: string;
1161
+
1162
+ // Event handlers
1163
+ onMove?: MoveHandler;
1164
+ onMoveEnd?: MoveEndHandler;
1165
+ onChange?: ChangeHandler;
1166
+ onDragStart?: DragStartHandler;
1167
+ onDragMove?: DragMoveHandler;
1168
+ onDrop?: DropHandler;
1169
+ onSnapbackEnd?: SnapbackEndHandler;
1170
+ onSquareClick?: SquareClickHandler;
1171
+ onSquareOver?: SquareOverHandler;
1172
+ onSquareOut?: SquareOutHandler;
1173
+ }
1174
+
1175
+ export type AnimationEasing = 'ease' | 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
1176
+
1177
+ export type AnimationDuration = 'fast' | 'normal' | 'slow';
1178
+
1179
+ export interface MoveEvent {
1180
+ from: string;
1181
+ to: string;
1182
+ piece: string;
1183
+ captured?: string;
1184
+ promotion?: string;
1185
+ }
1186
+
1187
+ export type MoveHandler = (move: MoveEvent) => boolean | Promise<boolean>;
1188
+
1189
+ export type MoveEndHandler = (move: MoveEvent) => void;
1190
+
1191
+ export interface ChessboardAPI {
1192
+ // Position methods
1193
+ position(): string;
1194
+ position(fen: string, animate?: boolean): void;
1195
+
1196
+ // Piece methods
1197
+ get(square: string): string | null;
1198
+ put(piece: string, square: string, animate?: boolean): void;
1199
+ remove(square: string, animate?: boolean): string | null;
1200
+
1201
+ // Board control
1202
+ clear(animate?: boolean): void;
1203
+ reset(animate?: boolean): void;
1204
+ flip(animate?: boolean): void;
1205
+
1206
+ // Moves
1207
+ move(from: string, to: string, animate?: boolean): Promise<MoveResult>;
1208
+
1209
+ // Utilities
1210
+ resize(size: number | 'auto'): void;
1211
+ destroy(): void;
1212
+
1213
+ // Chess.js integration
1214
+ fen(): string;
1215
+ turn(): 'w' | 'b';
1216
+ moves(options?: MovesOptions): string[];
1217
+ history(options?: HistoryOptions): string[] | MoveEvent[];
1218
+ isGameOver(): boolean;
1219
+ isCheckmate(): boolean;
1220
+ isDraw(): boolean;
1221
+ }
1222
+ ```
1223
+
1224
+ ---
1225
+
1226
+ ## 🚀 Build e Deployment
1227
+
1228
+ ### 1. Configurazione Rollup Avanzata
1229
+
1230
+ ```javascript
1231
+ // config/rollup.config.js
1232
+ import { defineConfig } from 'rollup';
1233
+ import resolve from '@rollup/plugin-node-resolve';
1234
+ import commonjs from '@rollup/plugin-commonjs';
1235
+ import terser from '@rollup/plugin-terser';
1236
+ import babel from '@rollup/plugin-babel';
1237
+ import typescript from '@rollup/plugin-typescript';
1238
+ import postcss from 'rollup-plugin-postcss';
1239
+ import { visualizer } from 'rollup-plugin-visualizer';
1240
+ import filesize from 'rollup-plugin-filesize';
1241
+
1242
+ const isProduction = process.env.NODE_ENV === 'production';
1243
+ const isDevelopment = process.env.NODE_ENV === 'development';
1244
+
1245
+ const baseConfig = {
1246
+ input: 'src/index.js',
1247
+ external: ['chess.js'],
1248
+ plugins: [
1249
+ resolve({
1250
+ browser: true,
1251
+ preferBuiltins: false
1252
+ }),
1253
+ commonjs(),
1254
+ typescript({
1255
+ tsconfig: './config/tsconfig.json',
1256
+ declaration: true,
1257
+ declarationDir: './dist/types'
1258
+ }),
1259
+ babel({
1260
+ babelHelpers: 'bundled',
1261
+ exclude: 'node_modules/**',
1262
+ configFile: './config/babel.config.js'
1263
+ }),
1264
+ postcss({
1265
+ extract: true,
1266
+ minimize: isProduction,
1267
+ sourceMap: !isProduction
1268
+ }),
1269
+ ...(isProduction ? [
1270
+ terser({
1271
+ compress: {
1272
+ drop_console: true,
1273
+ drop_debugger: true,
1274
+ pure_funcs: ['console.log', 'console.debug']
1275
+ },
1276
+ format: {
1277
+ comments: false
1278
+ }
1279
+ }),
1280
+ visualizer({
1281
+ filename: 'dist/bundle-analysis.html',
1282
+ open: false,
1283
+ gzipSize: true
1284
+ }),
1285
+ filesize()
1286
+ ] : [])
1287
+ ]
1288
+ };
1289
+
1290
+ export default defineConfig([
1291
+ // ES Modules
1292
+ {
1293
+ ...baseConfig,
1294
+ output: {
1295
+ file: 'dist/chessboard.esm.js',
1296
+ format: 'esm',
1297
+ sourcemap: !isProduction
1298
+ }
1299
+ },
1300
+
1301
+ // CommonJS
1302
+ {
1303
+ ...baseConfig,
1304
+ output: {
1305
+ file: 'dist/chessboard.cjs.js',
1306
+ format: 'cjs',
1307
+ exports: 'auto',
1308
+ sourcemap: !isProduction
1309
+ }
1310
+ },
1311
+
1312
+ // UMD
1313
+ {
1314
+ ...baseConfig,
1315
+ output: {
1316
+ file: 'dist/chessboard.umd.js',
1317
+ format: 'umd',
1318
+ name: 'Chessboard',
1319
+ globals: {
1320
+ 'chess.js': 'Chess'
1321
+ },
1322
+ sourcemap: !isProduction
1323
+ }
1324
+ },
1325
+
1326
+ // IIFE (Browser)
1327
+ {
1328
+ ...baseConfig,
1329
+ output: {
1330
+ file: 'dist/chessboard.iife.js',
1331
+ format: 'iife',
1332
+ name: 'Chessboard',
1333
+ globals: {
1334
+ 'chess.js': 'Chess'
1335
+ },
1336
+ sourcemap: !isProduction
1337
+ }
1338
+ },
1339
+
1340
+ // Minified versions for production
1341
+ ...(isProduction ? [
1342
+ {
1343
+ ...baseConfig,
1344
+ output: {
1345
+ file: 'dist/chessboard.min.js',
1346
+ format: 'iife',
1347
+ name: 'Chessboard',
1348
+ globals: {
1349
+ 'chess.js': 'Chess'
1350
+ }
1351
+ }
1352
+ }
1353
+ ] : [])
1354
+ ]);
1355
+ ```
1356
+
1357
+ ### 2. CI/CD Pipeline (GitHub Actions)
1358
+
1359
+ ```yaml
1360
+ # .github/workflows/ci.yml
1361
+ name: CI/CD Pipeline
1362
+
1363
+ on:
1364
+ push:
1365
+ branches: [main, develop]
1366
+ pull_request:
1367
+ branches: [main]
1368
+
1369
+ env:
1370
+ NODE_VERSION: '18'
1371
+
1372
+ jobs:
1373
+ lint:
1374
+ name: Code Quality
1375
+ runs-on: ubuntu-latest
1376
+ steps:
1377
+ - uses: actions/checkout@v4
1378
+
1379
+ - name: Setup Node.js
1380
+ uses: actions/setup-node@v4
1381
+ with:
1382
+ node-version: ${{ env.NODE_VERSION }}
1383
+ cache: 'npm'
1384
+
1385
+ - name: Install dependencies
1386
+ run: npm ci
1387
+
1388
+ - name: ESLint
1389
+ run: npm run lint
1390
+
1391
+ - name: Prettier
1392
+ run: npm run format:check
1393
+
1394
+ - name: TypeScript Check
1395
+ run: npm run typecheck
1396
+
1397
+ test:
1398
+ name: Test Suite
1399
+ runs-on: ubuntu-latest
1400
+ strategy:
1401
+ matrix:
1402
+ test-type: [unit, integration, e2e]
1403
+ steps:
1404
+ - uses: actions/checkout@v4
1405
+
1406
+ - name: Setup Node.js
1407
+ uses: actions/setup-node@v4
1408
+ with:
1409
+ node-version: ${{ env.NODE_VERSION }}
1410
+ cache: 'npm'
1411
+
1412
+ - name: Install dependencies
1413
+ run: npm ci
1414
+
1415
+ - name: Install Playwright (E2E only)
1416
+ if: matrix.test-type == 'e2e'
1417
+ run: npx playwright install
1418
+
1419
+ - name: Run tests
1420
+ run: npm run test:${{ matrix.test-type }}
1421
+
1422
+ - name: Upload coverage
1423
+ if: matrix.test-type == 'unit'
1424
+ uses: codecov/codecov-action@v3
1425
+ with:
1426
+ file: ./coverage/lcov.info
1427
+
1428
+ build:
1429
+ name: Build
1430
+ runs-on: ubuntu-latest
1431
+ needs: [lint, test]
1432
+ steps:
1433
+ - uses: actions/checkout@v4
1434
+
1435
+ - name: Setup Node.js
1436
+ uses: actions/setup-node@v4
1437
+ with:
1438
+ node-version: ${{ env.NODE_VERSION }}
1439
+ cache: 'npm'
1440
+
1441
+ - name: Install dependencies
1442
+ run: npm ci
1443
+
1444
+ - name: Build
1445
+ run: npm run build
1446
+
1447
+ - name: Size Check
1448
+ run: npm run size-check
1449
+
1450
+ - name: Upload build artifacts
1451
+ uses: actions/upload-artifact@v3
1452
+ with:
1453
+ name: dist
1454
+ path: dist/
1455
+
1456
+ performance:
1457
+ name: Performance Audit
1458
+ runs-on: ubuntu-latest
1459
+ needs: [build]
1460
+ steps:
1461
+ - uses: actions/checkout@v4
1462
+
1463
+ - name: Setup Node.js
1464
+ uses: actions/setup-node@v4
1465
+ with:
1466
+ node-version: ${{ env.NODE_VERSION }}
1467
+ cache: 'npm'
1468
+
1469
+ - name: Install dependencies
1470
+ run: npm ci
1471
+
1472
+ - name: Download build artifacts
1473
+ uses: actions/download-artifact@v3
1474
+ with:
1475
+ name: dist
1476
+ path: dist/
1477
+
1478
+ - name: Performance benchmarks
1479
+ run: npm run test:performance
1480
+
1481
+ - name: Lighthouse audit
1482
+ run: npm run perf-audit
1483
+
1484
+ release:
1485
+ name: Release
1486
+ runs-on: ubuntu-latest
1487
+ needs: [build, performance]
1488
+ if: github.ref == 'refs/heads/main'
1489
+ steps:
1490
+ - uses: actions/checkout@v4
1491
+ with:
1492
+ token: ${{ secrets.GITHUB_TOKEN }}
1493
+
1494
+ - name: Setup Node.js
1495
+ uses: actions/setup-node@v4
1496
+ with:
1497
+ node-version: ${{ env.NODE_VERSION }}
1498
+ cache: 'npm'
1499
+ registry-url: 'https://registry.npmjs.org'
1500
+
1501
+ - name: Install dependencies
1502
+ run: npm ci
1503
+
1504
+ - name: Download build artifacts
1505
+ uses: actions/download-artifact@v3
1506
+ with:
1507
+ name: dist
1508
+ path: dist/
1509
+
1510
+ - name: Semantic Release
1511
+ run: npx semantic-release
1512
+ env:
1513
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1514
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
1515
+ ```
1516
+
1517
+ ---
1518
+
1519
+ ## 🔍 Monitoring e Analytics
1520
+
1521
+ ### 1. Performance Monitoring
1522
+
1523
+ ```javascript
1524
+ // src/utils/performance.js
1525
+ export class PerformanceMonitor {
1526
+ constructor() {
1527
+ this.metrics = new Map();
1528
+ this.observers = new Map();
1529
+ this.setupObservers();
1530
+ }
1531
+
1532
+ setupObservers() {
1533
+ // Performance Observer for paint metrics
1534
+ if ('PerformanceObserver' in window) {
1535
+ const paintObserver = new PerformanceObserver((list) => {
1536
+ list.getEntries().forEach((entry) => {
1537
+ this.recordMetric(`paint.${entry.name}`, entry.startTime);
1538
+ });
1539
+ });
1540
+ paintObserver.observe({ entryTypes: ['paint'] });
1541
+ this.observers.set('paint', paintObserver);
1542
+
1543
+ // Long task observer
1544
+ const longTaskObserver = new PerformanceObserver((list) => {
1545
+ list.getEntries().forEach((entry) => {
1546
+ this.recordMetric('long-task', entry.duration);
1547
+ });
1548
+ });
1549
+ longTaskObserver.observe({ entryTypes: ['longtask'] });
1550
+ this.observers.set('longtask', longTaskObserver);
1551
+ }
1552
+ }
1553
+
1554
+ startMeasure(name) {
1555
+ performance.mark(`${name}-start`);
1556
+ }
1557
+
1558
+ endMeasure(name) {
1559
+ performance.mark(`${name}-end`);
1560
+ performance.measure(name, `${name}-start`, `${name}-end`);
1561
+
1562
+ const measure = performance.getEntriesByName(name, 'measure')[0];
1563
+ this.recordMetric(name, measure.duration);
1564
+
1565
+ return measure.duration;
1566
+ }
1567
+
1568
+ recordMetric(name, value) {
1569
+ if (!this.metrics.has(name)) {
1570
+ this.metrics.set(name, []);
1571
+ }
1572
+
1573
+ this.metrics.get(name).push({
1574
+ value,
1575
+ timestamp: Date.now(),
1576
+ url: window.location.href
1577
+ });
1578
+ }
1579
+
1580
+ getMetrics() {
1581
+ const summary = {};
1582
+
1583
+ for (const [name, values] of this.metrics) {
1584
+ const numbers = values.map(v => v.value);
1585
+ summary[name] = {
1586
+ count: numbers.length,
1587
+ mean: numbers.reduce((a, b) => a + b, 0) / numbers.length,
1588
+ min: Math.min(...numbers),
1589
+ max: Math.max(...numbers),
1590
+ p95: this.percentile(numbers, 95)
1591
+ };
1592
+ }
1593
+
1594
+ return summary;
1595
+ }
1596
+ }
1597
+ ```
1598
+
1599
+ ### 2. Error Tracking
1600
+
1601
+ ```javascript
1602
+ // src/utils/errorTracking.js
1603
+ export class ErrorTracker {
1604
+ constructor(config = {}) {
1605
+ this.config = {
1606
+ reportToConsole: true,
1607
+ reportToServer: false,
1608
+ serverEndpoint: null,
1609
+ ...config
1610
+ };
1611
+
1612
+ this.setupErrorHandlers();
1613
+ }
1614
+
1615
+ setupErrorHandlers() {
1616
+ // Global error handler
1617
+ window.addEventListener('error', (event) => {
1618
+ this.reportError({
1619
+ type: 'javascript',
1620
+ message: event.message,
1621
+ filename: event.filename,
1622
+ lineno: event.lineno,
1623
+ colno: event.colno,
1624
+ stack: event.error?.stack
1625
+ });
1626
+ });
1627
+
1628
+ // Unhandled promise rejection
1629
+ window.addEventListener('unhandledrejection', (event) => {
1630
+ this.reportError({
1631
+ type: 'promise',
1632
+ message: event.reason?.message || 'Unhandled promise rejection',
1633
+ stack: event.reason?.stack
1634
+ });
1635
+ });
1636
+ }
1637
+
1638
+ reportError(error) {
1639
+ const errorReport = {
1640
+ ...error,
1641
+ timestamp: new Date().toISOString(),
1642
+ url: window.location.href,
1643
+ userAgent: navigator.userAgent,
1644
+ component: 'chessboard.js'
1645
+ };
1646
+
1647
+ if (this.config.reportToConsole) {
1648
+ console.error('Chessboard.js Error:', errorReport);
1649
+ }
1650
+
1651
+ if (this.config.reportToServer && this.config.serverEndpoint) {
1652
+ this.sendToServer(errorReport);
1653
+ }
1654
+ }
1655
+
1656
+ async sendToServer(errorReport) {
1657
+ try {
1658
+ await fetch(this.config.serverEndpoint, {
1659
+ method: 'POST',
1660
+ headers: {
1661
+ 'Content-Type': 'application/json'
1662
+ },
1663
+ body: JSON.stringify(errorReport)
1664
+ });
1665
+ } catch (e) {
1666
+ console.warn('Failed to send error report to server:', e);
1667
+ }
1668
+ }
1669
+ }
1670
+ ```
1671
+