respira/src/formats/import/pyodideLoader.ts
Jan-Henrik Bruhn 11b710eb17 feature: Reorganize code into formats folder structure
Moved embroidery format-related code from utils to new formats folder:

Structure:
- src/formats/pen/ - PEN format encoding and parsing
  - encoder.ts (was utils/penEncoder.ts)
  - encoder.test.ts (was utils/penEncoder.test.ts)
  - parser.ts (was utils/penParser.ts)
  - PEN constants moved inline to encoder.ts

- src/formats/import/ - Pattern import/conversion (currently PES)
  - worker.ts (was workers/patternConverter.worker.ts)
  - client.ts (was utils/patternConverterClient.ts)
  - pesImporter.ts (was utils/pystitchConverter.ts)
  - pyodideLoader.ts (was utils/pyodideLoader.ts)
  - constants.ts (PyStitch/pyembroidery constants)

Benefits:
- Better separation of concerns
- PEN encoder is co-located with PEN parser
- Import logic is in one place and extensible for other formats
- Removed utils/embroideryConstants.ts - split into appropriate locations
- Updated all 18 import references across the codebase

All tests passing, build successful.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-14 12:19:21 +01:00

90 lines
2.4 KiB
TypeScript

import { loadPyodide, type PyodideInterface } from "pyodide";
export type PyodideState = "not_loaded" | "loading" | "ready" | "error";
class PyodideLoader {
private pyodide: PyodideInterface | null = null;
private state: PyodideState = "not_loaded";
private error: string | null = null;
private loadPromise: Promise<PyodideInterface> | null = null;
/**
* Get the current Pyodide state
*/
getState(): PyodideState {
return this.state;
}
/**
* Get the error message if state is 'error'
*/
getError(): string | null {
return this.error;
}
/**
* Initialize Pyodide and install PyStitch
*/
async initialize(): Promise<PyodideInterface> {
// If already ready, return immediately
if (this.state === "ready" && this.pyodide) {
return this.pyodide;
}
// If currently loading, wait for the existing promise
if (this.loadPromise) {
return this.loadPromise;
}
// Start loading
this.state = "loading";
this.error = null;
this.loadPromise = (async () => {
try {
console.log("[PyodideLoader] Loading Pyodide...");
// Load Pyodide with CDN indexURL for packages
// The core files will be loaded from our bundle, but packages will come from CDN
this.pyodide = await loadPyodide();
console.log("[PyodideLoader] Pyodide loaded, loading micropip...");
// Load micropip package
/*await this.pyodide.loadPackage('micropip');
console.log('[PyodideLoader] Installing PyStitch...');
// Install PyStitch using micropip
await this.pyodide.runPythonAsync(`
import micropip
await micropip.install('pystitch')
`);*/
await this.pyodide.loadPackage("pystitch-1.0.0-py3-none-any.whl");
console.log("[PyodideLoader] PyStitch installed successfully");
this.state = "ready";
return this.pyodide;
} catch (err) {
this.state = "error";
this.error =
err instanceof Error ? err.message : "Unknown error loading Pyodide";
console.error("[PyodideLoader] Error:", this.error);
throw err;
}
})();
return this.loadPromise;
}
/**
* Get the Pyodide instance (must be initialized first)
*/
getInstance(): PyodideInterface | null {
return this.pyodide;
}
}
// Export singleton instance
export const pyodideLoader = new PyodideLoader();