ether-to-astro 1.0.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.
Files changed (138) hide show
  1. package/.env.example +13 -0
  2. package/.github/pull_request_template.md +16 -0
  3. package/.github/workflows/release.yml +35 -0
  4. package/.github/workflows/test.yml +32 -0
  5. package/AGENTS.md +99 -0
  6. package/LICENSE +18 -0
  7. package/NOTICE.md +45 -0
  8. package/README.md +301 -0
  9. package/SETUP.md +70 -0
  10. package/TESTING_SUMMARY.md +238 -0
  11. package/TEST_SUITE_STATUS.md +218 -0
  12. package/biome.json +48 -0
  13. package/dist/astro-service.d.ts +98 -0
  14. package/dist/astro-service.js +496 -0
  15. package/dist/chart-types.d.ts +52 -0
  16. package/dist/chart-types.js +51 -0
  17. package/dist/charts.d.ts +125 -0
  18. package/dist/charts.js +324 -0
  19. package/dist/cli.d.ts +7 -0
  20. package/dist/cli.js +472 -0
  21. package/dist/constants.d.ts +81 -0
  22. package/dist/constants.js +76 -0
  23. package/dist/eclipses.d.ts +85 -0
  24. package/dist/eclipses.js +184 -0
  25. package/dist/ephemeris.d.ts +120 -0
  26. package/dist/ephemeris.js +379 -0
  27. package/dist/formatter.d.ts +2 -0
  28. package/dist/formatter.js +22 -0
  29. package/dist/houses.d.ts +82 -0
  30. package/dist/houses.js +169 -0
  31. package/dist/index.d.ts +14 -0
  32. package/dist/index.js +150 -0
  33. package/dist/loader.d.ts +2 -0
  34. package/dist/loader.js +31 -0
  35. package/dist/logger.d.ts +25 -0
  36. package/dist/logger.js +73 -0
  37. package/dist/profile-store.d.ts +48 -0
  38. package/dist/profile-store.js +156 -0
  39. package/dist/riseset.d.ts +82 -0
  40. package/dist/riseset.js +185 -0
  41. package/dist/storage.d.ts +10 -0
  42. package/dist/storage.js +40 -0
  43. package/dist/time-utils.d.ts +68 -0
  44. package/dist/time-utils.js +136 -0
  45. package/dist/tool-registry.d.ts +35 -0
  46. package/dist/tool-registry.js +307 -0
  47. package/dist/tool-result.d.ts +175 -0
  48. package/dist/tool-result.js +188 -0
  49. package/dist/transits.d.ts +108 -0
  50. package/dist/transits.js +263 -0
  51. package/dist/types.d.ts +450 -0
  52. package/dist/types.js +161 -0
  53. package/example-usage.md +131 -0
  54. package/natal-chart.json +187 -0
  55. package/package.json +61 -0
  56. package/scripts/download-ephemeris.js +115 -0
  57. package/setup.sh +21 -0
  58. package/src/astro-service.ts +710 -0
  59. package/src/chart-types.ts +125 -0
  60. package/src/charts.ts +399 -0
  61. package/src/cli.ts +694 -0
  62. package/src/constants.ts +89 -0
  63. package/src/eclipses.ts +226 -0
  64. package/src/ephemeris.ts +437 -0
  65. package/src/formatter.ts +25 -0
  66. package/src/houses.ts +202 -0
  67. package/src/index.ts +170 -0
  68. package/src/loader.ts +36 -0
  69. package/src/logger.ts +104 -0
  70. package/src/profile-store.ts +285 -0
  71. package/src/riseset.ts +229 -0
  72. package/src/time-utils.ts +167 -0
  73. package/src/tool-registry.ts +357 -0
  74. package/src/tool-result.ts +283 -0
  75. package/src/transits.ts +352 -0
  76. package/src/types.ts +547 -0
  77. package/tests/README.md +173 -0
  78. package/tests/TESTING_STRATEGY.md +178 -0
  79. package/tests/fixtures/bowen-yang-chart.ts +69 -0
  80. package/tests/fixtures/calculate-expected.ts +81 -0
  81. package/tests/fixtures/expected-results.ts +117 -0
  82. package/tests/fixtures/generate-expected-simple.ts +94 -0
  83. package/tests/helpers/date-fixtures.ts +15 -0
  84. package/tests/helpers/ephem.ts +11 -0
  85. package/tests/helpers/temp.ts +9 -0
  86. package/tests/setup.ts +11 -0
  87. package/tests/unit/astro-service.test.ts +323 -0
  88. package/tests/unit/chart-types.test.ts +18 -0
  89. package/tests/unit/charts-errors.test.ts +42 -0
  90. package/tests/unit/charts.test.ts +157 -0
  91. package/tests/unit/cli-commands.test.ts +82 -0
  92. package/tests/unit/cli-profiles.test.ts +128 -0
  93. package/tests/unit/cli.test.ts +191 -0
  94. package/tests/unit/constants.test.ts +26 -0
  95. package/tests/unit/correctness-critical.test.ts +408 -0
  96. package/tests/unit/eclipses.test.ts +108 -0
  97. package/tests/unit/ephemeris.test.ts +213 -0
  98. package/tests/unit/error-handling.test.ts +116 -0
  99. package/tests/unit/formatter.test.ts +29 -0
  100. package/tests/unit/houses-errors.test.ts +27 -0
  101. package/tests/unit/houses-validation.test.ts +164 -0
  102. package/tests/unit/houses.test.ts +205 -0
  103. package/tests/unit/profile-store.test.ts +163 -0
  104. package/tests/unit/real-user-charts.test.ts +148 -0
  105. package/tests/unit/riseset.test.ts +106 -0
  106. package/tests/unit/solver-edges.test.ts +197 -0
  107. package/tests/unit/time-utils-temporal.test.ts +303 -0
  108. package/tests/unit/time-utils.test.ts +173 -0
  109. package/tests/unit/tool-registry.test.ts +222 -0
  110. package/tests/unit/tool-result.test.ts +45 -0
  111. package/tests/unit/transit-correctness.test.ts +78 -0
  112. package/tests/unit/transits.test.ts +238 -0
  113. package/tests/validation/README.md +32 -0
  114. package/tests/validation/adapters/astrolog.ts +306 -0
  115. package/tests/validation/adapters/internal.ts +184 -0
  116. package/tests/validation/compare/eclipses.ts +47 -0
  117. package/tests/validation/compare/houses.ts +76 -0
  118. package/tests/validation/compare/positions.ts +104 -0
  119. package/tests/validation/compare/riseSet.ts +48 -0
  120. package/tests/validation/compare/roots.ts +90 -0
  121. package/tests/validation/compare/transits.ts +69 -0
  122. package/tests/validation/fixtures/astrolog-parity/core.ts +194 -0
  123. package/tests/validation/fixtures/eclipses/core.ts +14 -0
  124. package/tests/validation/fixtures/houses/core.ts +47 -0
  125. package/tests/validation/fixtures/positions/core.ts +159 -0
  126. package/tests/validation/fixtures/rise-set/core.ts +20 -0
  127. package/tests/validation/fixtures/roots/core.ts +47 -0
  128. package/tests/validation/fixtures/transits/core.ts +61 -0
  129. package/tests/validation/fixtures/transits/dst.ts +21 -0
  130. package/tests/validation/oracle.spec.ts +129 -0
  131. package/tests/validation/utils/denseRootOracle.ts +269 -0
  132. package/tests/validation/utils/fixtureTypes.ts +146 -0
  133. package/tests/validation/utils/report.ts +60 -0
  134. package/tests/validation/utils/tolerances.ts +23 -0
  135. package/tests/validation/validation.spec.ts +836 -0
  136. package/tools/color-picker.html +388 -0
  137. package/tsconfig.json +17 -0
  138. package/vitest.config.ts +31 -0
@@ -0,0 +1,125 @@
1
+ import { type ChartFormat, type ChartTheme } from './chart-types.js';
2
+ import type { EphemerisCalculator } from './ephemeris.js';
3
+ import type { HouseCalculator } from './houses.js';
4
+ import { type NatalChart } from './types.js';
5
+ /**
6
+ * Renderer for astrological charts using SVG
7
+ *
8
+ * @remarks
9
+ * Generates natal and transit charts as SVG images using the astrochart library.
10
+ * Converts SVG to PNG/WebP formats for output. Uses JSDOM to provide
11
+ * browser environment for the chart library.
12
+ */
13
+ export declare class ChartRenderer {
14
+ /** Ephemeris calculator instance */
15
+ private ephem;
16
+ /** House calculator instance */
17
+ private houseCalc;
18
+ /** Virtual DOM for chart rendering */
19
+ private dom;
20
+ /**
21
+ * Create a new chart renderer
22
+ *
23
+ * @param ephem - Initialized ephemeris calculator
24
+ * @param houseCalc - Initialized house calculator
25
+ *
26
+ * @remarks
27
+ * Both calculators must be initialized before passing to the constructor.
28
+ * Sets up a virtual DOM environment for the astrochart library.
29
+ */
30
+ constructor(ephem: EphemerisCalculator, houseCalc: HouseCalculator);
31
+ /**
32
+ * Setup global browser variables for astrochart library
33
+ *
34
+ * @remarks
35
+ * The astrochart library expects browser globals like document and window.
36
+ * This method provides those from the virtual DOM. Required because
37
+ * astrochart was designed for browser environments.
38
+ */
39
+ private setupGlobals;
40
+ /**
41
+ * Clear the chart container element
42
+ *
43
+ * @remarks
44
+ * Removes any previous chart content to ensure clean rendering.
45
+ * Called before generating each new chart.
46
+ */
47
+ private clearContainer;
48
+ /**
49
+ * Generate a natal chart visualization
50
+ *
51
+ * @param natalChart - Birth chart data with julianDay and houseSystem
52
+ * @param theme - Visual theme for the chart (default: 'light')
53
+ * @param format - Output format (default: 'svg')
54
+ * @returns Chart image as buffer or data URL
55
+ * @throws Error if natal chart is invalid or rendering fails
56
+ *
57
+ * @remarks
58
+ * Renders a complete natal chart with planets, houses, and aspects.
59
+ * Requires julianDay to be set in the natalChart.
60
+ */
61
+ generateNatalChart(natalChart: NatalChart, theme?: ChartTheme, format?: ChartFormat): Promise<Buffer | string>;
62
+ /**
63
+ * Prepare chart data for astrochart library
64
+ *
65
+ * @param natalChart - Birth chart data
66
+ * @param transitDate - Optional date for transit calculations
67
+ * @returns Chart data in astrochart format
68
+ * @throws Error if julianDay is not set
69
+ *
70
+ * @remarks
71
+ * Converts internal chart format to astrochart's expected format.
72
+ * Includes planets, houses, and optionally transit positions.
73
+ */
74
+ private prepareChartData;
75
+ /**
76
+ * Generate a transit chart visualization
77
+ *
78
+ * @param natalChart - Birth chart data with julianDay and houseSystem
79
+ * @param transitDate - Date for transit calculation
80
+ * @param theme - Visual theme for the chart (default: 'light')
81
+ * @param format - Output format (default: 'svg')
82
+ * @returns Chart image as buffer or data URL
83
+ * @throws Error if natal chart is invalid or rendering fails
84
+ *
85
+ * @remarks
86
+ * Shows both natal positions (inner wheel) and current transits (outer wheel).
87
+ * Requires julianDay to be set in the natalChart.
88
+ */
89
+ generateTransitChart(natalChart: NatalChart, transitDate: Date, theme?: ChartTheme, format?: ChartFormat): Promise<Buffer | string>;
90
+ /**
91
+ * Map internal planet names to astrochart keys
92
+ *
93
+ * @param planetName - Internal planet name
94
+ * @returns Astrochart planet key or null if not supported
95
+ *
96
+ * @remarks
97
+ * Maps our planet names to the keys expected by astrochart.
98
+ * Uses mean node to avoid collision with true node.
99
+ */
100
+ private getPlanetKey;
101
+ /**
102
+ * Extract SVG string from virtual DOM
103
+ *
104
+ * @returns SVG string
105
+ * @throws Error if no SVG element found
106
+ *
107
+ * @remarks
108
+ * Finds the SVG element in the virtual DOM and returns
109
+ * its outer HTML. Throws if no chart was rendered.
110
+ */
111
+ private extractSVG;
112
+ /**
113
+ * Convert SVG to specified output format
114
+ *
115
+ * @param svg - SVG string or buffer
116
+ * @param format - Target output format
117
+ * @returns Converted image as buffer (png/webp) or data URL (svg)
118
+ * @throws Error if conversion fails
119
+ *
120
+ * @remarks
121
+ * Uses Sharp library for PNG/WebP conversion. SVG is returned
122
+ * as a data URL for direct use in web contexts.
123
+ */
124
+ private convertToImage;
125
+ }
package/dist/charts.js ADDED
@@ -0,0 +1,324 @@
1
+ import Chart from '@astrodraw/astrochart';
2
+ import { JSDOM } from 'jsdom';
3
+ import sharp from 'sharp';
4
+ import { getThemeSettings, } from './chart-types.js';
5
+ import { PLANETS } from './types.js';
6
+ /**
7
+ * Renderer for astrological charts using SVG
8
+ *
9
+ * @remarks
10
+ * Generates natal and transit charts as SVG images using the astrochart library.
11
+ * Converts SVG to PNG/WebP formats for output. Uses JSDOM to provide
12
+ * browser environment for the chart library.
13
+ */
14
+ export class ChartRenderer {
15
+ /** Ephemeris calculator instance */
16
+ ephem;
17
+ /** House calculator instance */
18
+ houseCalc;
19
+ /** Virtual DOM for chart rendering */
20
+ dom;
21
+ /**
22
+ * Create a new chart renderer
23
+ *
24
+ * @param ephem - Initialized ephemeris calculator
25
+ * @param houseCalc - Initialized house calculator
26
+ *
27
+ * @remarks
28
+ * Both calculators must be initialized before passing to the constructor.
29
+ * Sets up a virtual DOM environment for the astrochart library.
30
+ */
31
+ constructor(ephem, houseCalc) {
32
+ this.ephem = ephem;
33
+ this.houseCalc = houseCalc;
34
+ // Create virtual DOM
35
+ this.dom = new JSDOM('<!DOCTYPE html><html><body><div id="chart-container"></div></body></html>');
36
+ }
37
+ /**
38
+ * Setup global browser variables for astrochart library
39
+ *
40
+ * @remarks
41
+ * The astrochart library expects browser globals like document and window.
42
+ * This method provides those from the virtual DOM. Required because
43
+ * astrochart was designed for browser environments.
44
+ */
45
+ setupGlobals() {
46
+ // Set global document and window for astrochart
47
+ // Note: Required by astrochart library which expects browser globals
48
+ const g = global;
49
+ g.document = this.dom.window.document;
50
+ g.window = this.dom.window;
51
+ g.SVGElement = this.dom.window.SVGElement;
52
+ g.self = this.dom.window;
53
+ }
54
+ /**
55
+ * Clear the chart container element
56
+ *
57
+ * @remarks
58
+ * Removes any previous chart content to ensure clean rendering.
59
+ * Called before generating each new chart.
60
+ */
61
+ clearContainer() {
62
+ const container = this.dom.window.document.getElementById('chart-container');
63
+ if (container) {
64
+ container.innerHTML = '';
65
+ }
66
+ }
67
+ /**
68
+ * Generate a natal chart visualization
69
+ *
70
+ * @param natalChart - Birth chart data with julianDay and houseSystem
71
+ * @param theme - Visual theme for the chart (default: 'light')
72
+ * @param format - Output format (default: 'svg')
73
+ * @returns Chart image as buffer or data URL
74
+ * @throws Error if natal chart is invalid or rendering fails
75
+ *
76
+ * @remarks
77
+ * Renders a complete natal chart with planets, houses, and aspects.
78
+ * Requires julianDay to be set in the natalChart.
79
+ */
80
+ async generateNatalChart(natalChart, theme = 'light', format = 'svg') {
81
+ this.setupGlobals();
82
+ this.clearContainer();
83
+ // Require Julian Day (always set by set_natal_chart)
84
+ if (!natalChart.julianDay) {
85
+ throw new Error('Natal chart missing Julian Day - chart may be from old session. Please call set_natal_chart again.');
86
+ }
87
+ const jd = natalChart.julianDay;
88
+ // Get only renderable planet positions (those mapped in getPlanetKey)
89
+ const renderablePlanetIds = [
90
+ PLANETS.SUN,
91
+ PLANETS.MOON,
92
+ PLANETS.MERCURY,
93
+ PLANETS.VENUS,
94
+ PLANETS.MARS,
95
+ PLANETS.JUPITER,
96
+ PLANETS.SATURN,
97
+ PLANETS.URANUS,
98
+ PLANETS.NEPTUNE,
99
+ PLANETS.PLUTO,
100
+ PLANETS.CHIRON,
101
+ PLANETS.MEAN_NODE, // Use mean node, not true node
102
+ ];
103
+ const positions = this.ephem.getAllPlanets(jd, renderablePlanetIds);
104
+ // Get houses using stored house system preference
105
+ const houseSystem = natalChart.houseSystem || 'P';
106
+ const houses = this.houseCalc.calculateHouses(jd, natalChart.location.latitude, natalChart.location.longitude, houseSystem);
107
+ // Convert to AstroChart format
108
+ const data = {
109
+ planets: {},
110
+ cusps: Array.from(houses.cusps).slice(1, 13), // Houses 1-12
111
+ };
112
+ // Map planet positions
113
+ positions.forEach((p) => {
114
+ const planetKey = this.getPlanetKey(p.planet);
115
+ if (planetKey) {
116
+ data.planets[planetKey] = [p.longitude];
117
+ }
118
+ });
119
+ // Create chart with theme colors
120
+ const settings = {
121
+ SYMBOL_SCALE: 1.2,
122
+ STROKE_ONLY: false,
123
+ ...getThemeSettings(theme, false),
124
+ };
125
+ const ChartClass = (Chart.default ||
126
+ Chart);
127
+ const chart = new ChartClass('chart-container', 800, 800, settings);
128
+ // Generate SVG
129
+ const radix = chart.radix(data);
130
+ radix.aspects();
131
+ const svgString = this.extractSVG();
132
+ // Convert to requested format
133
+ if (format === 'svg') {
134
+ return svgString;
135
+ }
136
+ return this.convertToImage(svgString, format, theme);
137
+ }
138
+ /**
139
+ * Prepare chart data for astrochart library
140
+ *
141
+ * @param natalChart - Birth chart data
142
+ * @param transitDate - Optional date for transit calculations
143
+ * @returns Chart data in astrochart format
144
+ * @throws Error if julianDay is not set
145
+ *
146
+ * @remarks
147
+ * Converts internal chart format to astrochart's expected format.
148
+ * Includes planets, houses, and optionally transit positions.
149
+ */
150
+ prepareChartData(natalChart, transitDate) {
151
+ // Require Julian Day (always set by set_natal_chart)
152
+ if (!natalChart.julianDay) {
153
+ throw new Error('Natal chart missing Julian Day - chart may be from old session. Please call set_natal_chart again.');
154
+ }
155
+ const jd = natalChart.julianDay;
156
+ // Get houses using stored house system preference
157
+ const houseSystem = natalChart.houseSystem || 'P';
158
+ const houses = this.houseCalc.calculateHouses(jd, natalChart.location.latitude, natalChart.location.longitude, houseSystem);
159
+ // Convert to AstroChart format
160
+ const data = {
161
+ planets: {},
162
+ cusps: Array.from(houses.cusps).slice(1, 13), // Houses 1-12
163
+ };
164
+ // Define renderable planets for charts
165
+ const renderablePlanetIds = [
166
+ PLANETS.SUN,
167
+ PLANETS.MOON,
168
+ PLANETS.MERCURY,
169
+ PLANETS.VENUS,
170
+ PLANETS.MARS,
171
+ PLANETS.JUPITER,
172
+ PLANETS.SATURN,
173
+ PLANETS.URANUS,
174
+ PLANETS.NEPTUNE,
175
+ PLANETS.PLUTO,
176
+ PLANETS.CHIRON,
177
+ PLANETS.MEAN_NODE,
178
+ ];
179
+ // Prefill natal planets from julianDay to ensure all renderable planets have positions
180
+ // This avoids fake 0° placeholders for planets missing from natalChart.planets
181
+ const natalPositions = this.ephem.getAllPlanets(jd, renderablePlanetIds);
182
+ natalPositions.forEach((p) => {
183
+ const planetKey = this.getPlanetKey(p.planet);
184
+ if (planetKey) {
185
+ data.planets[planetKey] = [p.longitude];
186
+ }
187
+ });
188
+ // Add transit planets if transit date provided
189
+ if (transitDate) {
190
+ const transitJD = this.ephem.dateToJulianDay(transitDate);
191
+ const transitPositions = this.ephem.getAllPlanets(transitJD, renderablePlanetIds);
192
+ transitPositions.forEach((p) => {
193
+ const planetKey = this.getPlanetKey(p.planet);
194
+ if (planetKey) {
195
+ // Add transit position as second element in array
196
+ // Natal position already exists from prefill above
197
+ const current = data.planets[planetKey];
198
+ if (current) {
199
+ data.planets[planetKey] = [current[0], p.longitude];
200
+ }
201
+ }
202
+ });
203
+ }
204
+ return data;
205
+ }
206
+ /**
207
+ * Generate a transit chart visualization
208
+ *
209
+ * @param natalChart - Birth chart data with julianDay and houseSystem
210
+ * @param transitDate - Date for transit calculation
211
+ * @param theme - Visual theme for the chart (default: 'light')
212
+ * @param format - Output format (default: 'svg')
213
+ * @returns Chart image as buffer or data URL
214
+ * @throws Error if natal chart is invalid or rendering fails
215
+ *
216
+ * @remarks
217
+ * Shows both natal positions (inner wheel) and current transits (outer wheel).
218
+ * Requires julianDay to be set in the natalChart.
219
+ */
220
+ async generateTransitChart(natalChart, transitDate, theme = 'light', format = 'svg') {
221
+ this.setupGlobals();
222
+ this.clearContainer();
223
+ const data = this.prepareChartData(natalChart, transitDate);
224
+ // Create chart with theme colors
225
+ const settings = {
226
+ SYMBOL_SCALE: 1.2,
227
+ STROKE_ONLY: false,
228
+ ...getThemeSettings(theme, false),
229
+ };
230
+ const ChartClass = (Chart.default ||
231
+ Chart);
232
+ const chart = new ChartClass('chart-container', 800, 800, settings);
233
+ // Generate SVG
234
+ const radix = chart.radix(data);
235
+ radix.aspects();
236
+ radix.transit(data);
237
+ const svgString = this.extractSVG();
238
+ // Convert to requested format
239
+ if (format === 'svg') {
240
+ return svgString;
241
+ }
242
+ return this.convertToImage(svgString, format, theme);
243
+ }
244
+ /**
245
+ * Map internal planet names to astrochart keys
246
+ *
247
+ * @param planetName - Internal planet name
248
+ * @returns Astrochart planet key or null if not supported
249
+ *
250
+ * @remarks
251
+ * Maps our planet names to the keys expected by astrochart.
252
+ * Uses mean node to avoid collision with true node.
253
+ */
254
+ getPlanetKey(planetName) {
255
+ const mapping = {
256
+ Sun: 'Sun',
257
+ Moon: 'Moon',
258
+ Mercury: 'Mercury',
259
+ Venus: 'Venus',
260
+ Mars: 'Mars',
261
+ Jupiter: 'Jupiter',
262
+ Saturn: 'Saturn',
263
+ Uranus: 'Uranus',
264
+ Neptune: 'Neptune',
265
+ Pluto: 'Pluto',
266
+ Chiron: 'Chiron',
267
+ 'North Node (Mean)': 'NNode', // Use mean node for consistency
268
+ // True node intentionally omitted - prevents collision/overwrite
269
+ };
270
+ return mapping[planetName] || null;
271
+ }
272
+ /**
273
+ * Extract SVG string from virtual DOM
274
+ *
275
+ * @returns SVG string
276
+ * @throws Error if no SVG element found
277
+ *
278
+ * @remarks
279
+ * Finds the SVG element in the virtual DOM and returns
280
+ * its outer HTML. Throws if no chart was rendered.
281
+ */
282
+ extractSVG() {
283
+ // Get the SVG element from the virtual DOM
284
+ const container = this.dom.window.document.getElementById('chart-container');
285
+ if (!container) {
286
+ throw new Error('Chart container not found - DOM setup failed');
287
+ }
288
+ const svg = container.querySelector('svg');
289
+ if (!svg) {
290
+ throw new Error('Chart rendering failed - no SVG element generated by astrochart library');
291
+ }
292
+ return svg.outerHTML;
293
+ }
294
+ /**
295
+ * Convert SVG to specified output format
296
+ *
297
+ * @param svg - SVG string or buffer
298
+ * @param format - Target output format
299
+ * @returns Converted image as buffer (png/webp) or data URL (svg)
300
+ * @throws Error if conversion fails
301
+ *
302
+ * @remarks
303
+ * Uses Sharp library for PNG/WebP conversion. SVG is returned
304
+ * as a data URL for direct use in web contexts.
305
+ */
306
+ async convertToImage(svg, format, theme) {
307
+ const buffer = Buffer.from(svg);
308
+ // Use theme-appropriate background color
309
+ const bgColor = theme === 'dark'
310
+ ? { r: 40, g: 44, b: 52, alpha: 1 } // #282c34
311
+ : { r: 255, g: 255, b: 255, alpha: 1 }; // #ffffff
312
+ if (format === 'png') {
313
+ return sharp(buffer)
314
+ .flatten({ background: bgColor })
315
+ .png({ quality: 100, compressionLevel: 6 })
316
+ .toBuffer();
317
+ }
318
+ // WebP
319
+ return sharp(buffer)
320
+ .flatten({ background: bgColor })
321
+ .webp({ quality: 95, effort: 6 })
322
+ .toBuffer();
323
+ }
324
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ interface CliIO {
3
+ stdout: (msg: string) => void;
4
+ stderr: (msg: string) => void;
5
+ }
6
+ export declare function runCli(argv: string[], io?: CliIO): Promise<number>;
7
+ export {};