@ecopages/image-processor 0.2.1-beta.0 → 0.3.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/src/plugin.js CHANGED
@@ -1,21 +1,18 @@
1
- import path from "node:path";
2
- import { GENERATED_BASE_PATHS } from "@ecopages/core/constants";
3
- import { fileSystem } from "@ecopages/file-system";
4
- import {
5
- mergeProcessorOptions,
6
- Processor
7
- } from "@ecopages/core/plugins/processor";
8
- import { Logger } from "@ecopages/logger";
9
- import { createImagePlugin, createImagePluginBundler } from "./image-plugins.js";
10
- import { ImageProcessor } from "./image-processor.js";
11
- import { anyCaseToCamelCase } from "./utils.js";
12
- function resolveGeneratedPath(type, options) {
13
- const { root, module, subPath } = options;
14
- const parts = [root, GENERATED_BASE_PATHS[type], module, subPath].filter(Boolean);
15
- return path.join(...parts);
16
- }
17
- const logger = new Logger("[@ecopages/image-processor]", {
18
- debug: process.env.ECOPAGES_LOGGER_DEBUG === "true"
1
+ /**
2
+ * ImageProcessorPlugin
3
+ * @module @ecopages/image-processor
4
+ */
5
+ import path from 'node:path';
6
+ import { fileSystem } from '@ecopages/file-system';
7
+ import { mergeProcessorOptions, Processor, resolveGeneratedPath, writeGeneratedTypesPackage, } from '@ecopages/core/processor';
8
+ import { Logger } from '@ecopages/logger';
9
+ import { isEcopagesEnvEnabled } from '@ecopages/core/processor';
10
+ import { createImagePlugin, createImagePluginBundler } from './image-plugins.js';
11
+ import { ImageProcessor } from './image-processor.js';
12
+ import { getSourceImagePaths, loadProcessedImagesFromDisk } from './image-runtime-state.js';
13
+ import { anyCaseToCamelCase } from './utils.js';
14
+ const logger = new Logger('[@ecopages/image-processor]', {
15
+ debug: isEcopagesEnvEnabled('ECOPAGES_LOGGER_DEBUG'),
19
16
  });
20
17
  const IMAGE_VIRTUAL_MODULE_TYPES = `/**
21
18
  * ImageAttributes
@@ -62,216 +59,248 @@ type ImageSize = {
62
59
  width: number;
63
60
  label: string;
64
61
  };`;
65
- class ImageProcessorPlugin extends Processor {
66
- buildContributionsPrepared = false;
67
- resolvedConfig;
68
- processedImages = {};
69
- constructor(config) {
70
- const acceptedFormats = config.options?.acceptedFormats ?? ["jpg", "jpeg", "png", "webp"];
71
- const extensionPatterns = acceptedFormats.map((format) => `*.${format.replace(/^\./, "")}`);
72
- const defaultWatchConfig = {
73
- paths: [],
74
- extensions: acceptedFormats,
75
- onCreate: async (ctx) => this.process([ctx.path]),
76
- onChange: async (ctx) => this.process([ctx.path]),
77
- onDelete: async (ctx) => this.deleteProcessedImagesbyPath(ctx.path),
78
- onError: (error) => logger.error("Watcher error", { error })
79
- };
80
- super({
81
- ...config,
82
- name: "ecopages-image-processor",
83
- description: "A Processor for optimizing images.",
84
- capabilities: [
85
- {
86
- kind: "image",
87
- extensions: extensionPatterns
88
- }
89
- ],
90
- watch: config.watch ? mergeProcessorOptions(defaultWatchConfig, config.watch) : defaultWatchConfig
91
- });
92
- }
93
- get buildPlugins() {
94
- return [createImagePluginBundler(this.processedImages)];
95
- }
96
- get plugins() {
97
- return [createImagePlugin(this.processedImages)];
98
- }
99
- /**
100
- * Replaces image-map contents without swapping the backing object.
101
- *
102
- * @remarks
103
- * The build/runtime virtual-module plugins close over `processedImages`, so
104
- * mutating the existing object keeps those plugins live after preparation.
105
- */
106
- replaceProcessedImages(images) {
107
- for (const key of Object.keys(this.processedImages)) {
108
- delete this.processedImages[key];
109
- }
110
- Object.assign(this.processedImages, images);
111
- }
112
- /**
113
- * Prepares the image virtual-module state before config build seals the app
114
- * manifest.
115
- */
116
- async prepareBuildContributions() {
117
- if (this.buildContributionsPrepared) {
118
- return;
62
+ /**
63
+ * ImageProcessorPlugin
64
+ * A Processor for optimizing images.
65
+ */
66
+ export class ImageProcessorPlugin extends Processor {
67
+ resolvedConfig;
68
+ processedImages = {};
69
+ constructor(config) {
70
+ const acceptedFormats = config.options?.acceptedFormats ?? ['jpg', 'jpeg', 'png', 'webp'];
71
+ const extensionPatterns = acceptedFormats.map((format) => `*.${format.replace(/^\./, '')}`);
72
+ const defaultWatchConfig = {
73
+ paths: [],
74
+ extensions: acceptedFormats,
75
+ onChanges: async (changes) => this.handleImageChanges(changes),
76
+ onError: (error) => logger.error('Watcher error', { error }),
77
+ };
78
+ super({
79
+ ...config,
80
+ name: 'ecopages-image-processor',
81
+ capabilities: [
82
+ {
83
+ kind: 'image',
84
+ extensions: extensionPatterns,
85
+ },
86
+ ],
87
+ watch: config.watch ? mergeProcessorOptions(defaultWatchConfig, config.watch) : defaultWatchConfig,
88
+ });
119
89
  }
120
- if (!this.context) {
121
- throw new Error("ImageProcessor requires context to be set");
90
+ async handleImageChanges({ created, changed, deleted }) {
91
+ const changedImages = [...created, ...changed];
92
+ if (changedImages.length > 0) {
93
+ await this.process(changedImages);
94
+ }
95
+ for (const imagePath of deleted) {
96
+ await this.deleteProcessedImagesbyPath(imagePath);
97
+ }
122
98
  }
123
- logger.debug("Setting up image processor", {
124
- srcDir: this.context.srcDir,
125
- distDir: this.context.distDir
126
- });
127
- const defaultConfig = {
128
- sourceDir: `${this.context.srcDir}/public/assets/images`,
129
- outputDir: `${this.context.distDir}/assets/optimized`,
130
- publicPath: "/assets/optimized",
131
- sizes: [],
132
- quality: 80,
133
- format: "webp"
134
- };
135
- const config = this.options ? mergeProcessorOptions(defaultConfig, this.options) : defaultConfig;
136
- this.resolvedConfig = config;
137
- this.processor = new ImageProcessor(config, {
138
- readCache: (key) => this.readCache(key),
139
- writeCache: (key, data) => this.writeCache(key, data)
140
- });
141
- this.replaceProcessedImages(await this.processor.processDirectory());
142
- if (this.watchConfig) {
143
- this.watchConfig.paths = [config.sourceDir];
99
+ plugins() {
100
+ return [
101
+ { ...createImagePlugin(this.processedImages), environments: ['server'] },
102
+ { ...createImagePluginBundler(this.processedImages), environments: ['browser'] },
103
+ ];
144
104
  }
145
- this.dependencies = this.generateDependencies();
146
- this.generateTypes();
147
- this.buildContributionsPrepared = true;
148
- }
149
- getRuntimeVirtualModulePath() {
150
- if (!this.context) {
151
- throw new Error("ImageProcessor requires context to be set");
105
+ /**
106
+ * Replaces image-map contents without swapping the backing object.
107
+ *
108
+ * @remarks
109
+ * The build/runtime virtual-module plugins close over `processedImages`, so
110
+ * mutating the existing object keeps those plugins live after preparation.
111
+ */
112
+ replaceProcessedImages(images) {
113
+ for (const key of Object.keys(this.processedImages)) {
114
+ delete this.processedImages[key];
115
+ }
116
+ Object.assign(this.processedImages, images);
152
117
  }
153
- return resolveGeneratedPath("cache", {
154
- root: this.context.distDir,
155
- module: this.name,
156
- subPath: "virtual-module.ts"
157
- });
158
- }
159
- getGeneratedOutputPath(src) {
160
- if (!this.resolvedConfig) {
161
- throw new Error("ImageProcessor not initialized");
118
+ /**
119
+ * Resolves processor config and creates the sharp-backed worker instance.
120
+ */
121
+ initializeProcessor() {
122
+ if (this.processor && this.resolvedConfig) {
123
+ return;
124
+ }
125
+ if (!this.context) {
126
+ throw new Error('ImageProcessor requires context to be set');
127
+ }
128
+ logger.debug('Setting up image processor', {
129
+ srcDir: this.context.srcDir,
130
+ distDir: this.context.distDir,
131
+ });
132
+ const defaultConfig = {
133
+ sourceDir: `${this.context.srcDir}/public/assets/images`,
134
+ outputDir: `${this.context.distDir}/assets/optimized`,
135
+ publicPath: '/assets/optimized',
136
+ sizes: [],
137
+ quality: 80,
138
+ format: 'webp',
139
+ };
140
+ const config = this.options ? mergeProcessorOptions(defaultConfig, this.options) : defaultConfig;
141
+ this.resolvedConfig = config;
142
+ this.processor = new ImageProcessor(config, {
143
+ readCache: (key) => this.readCache(key),
144
+ writeCache: (key, data) => this.writeCache(key, data),
145
+ });
146
+ if (this.watchConfig) {
147
+ this.watchConfig.paths = [config.sourceDir];
148
+ }
162
149
  }
163
- return path.join(this.resolvedConfig.outputDir, path.basename(src));
164
- }
165
- hasGeneratedOutputs() {
166
- if (!this.resolvedConfig) {
167
- return false;
150
+ getRuntimeVirtualModulePath() {
151
+ if (!this.context) {
152
+ throw new Error('ImageProcessor requires context to be set');
153
+ }
154
+ return resolveGeneratedPath('cache', {
155
+ root: this.context.distDir,
156
+ module: this.name,
157
+ subPath: 'virtual-module.ts',
158
+ });
168
159
  }
169
- if (!fileSystem.exists(this.resolvedConfig.outputDir) || !fileSystem.exists(this.getRuntimeVirtualModulePath())) {
170
- return false;
160
+ getGeneratedOutputPath(src) {
161
+ if (!this.resolvedConfig) {
162
+ throw new Error('ImageProcessor not initialized');
163
+ }
164
+ return path.join(this.resolvedConfig.outputDir, path.basename(src));
171
165
  }
172
- return Object.values(this.processedImages).every((image) => {
173
- const outputPaths = [image.attributes.src, ...image.variants.map((variant) => variant.src)];
174
- return outputPaths.every((src) => fileSystem.exists(this.getGeneratedOutputPath(src)));
175
- });
176
- }
177
- async rehydrateGeneratedOutputs() {
178
- if (!this.processor) {
179
- throw new Error("ImageProcessor not initialized");
166
+ /**
167
+ * Restores in-memory image state from previously generated dist artifacts.
168
+ *
169
+ * @returns `true` when state was restored without invoking sharp.
170
+ */
171
+ async syncProcessedImagesFromDisk() {
172
+ if (!this.resolvedConfig) {
173
+ return false;
174
+ }
175
+ const sourceImages = await getSourceImagePaths(this.resolvedConfig);
176
+ const imageMap = await loadProcessedImagesFromDisk({
177
+ resolvedConfig: this.resolvedConfig,
178
+ runtimeVirtualModulePath: this.getRuntimeVirtualModulePath(),
179
+ });
180
+ if (imageMap === null) {
181
+ return false;
182
+ }
183
+ if (sourceImages.length > 0 && Object.keys(imageMap).length !== sourceImages.length) {
184
+ return false;
185
+ }
186
+ this.replaceProcessedImages(imageMap);
187
+ if (Object.keys(imageMap).length > 0) {
188
+ this.generateTypes();
189
+ }
190
+ return true;
180
191
  }
181
- if (this.hasGeneratedOutputs()) {
182
- return;
192
+ async ensureGeneratedOutputs() {
193
+ if (!this.processor) {
194
+ throw new Error('ImageProcessor not initialized');
195
+ }
196
+ if (await this.syncProcessedImagesFromDisk()) {
197
+ return;
198
+ }
199
+ this.replaceProcessedImages(await this.processor.processDirectory());
200
+ this.generateTypes();
183
201
  }
184
- this.replaceProcessedImages(await this.processor.processDirectory());
185
- this.dependencies = this.generateDependencies();
186
- this.generateTypes();
187
- }
188
- /**
189
- * Generate dependencies for processor.
190
- * It is ossible to define which one should be included in the final bundle based on the environment.
191
- * @returns
192
- */
193
- generateDependencies() {
194
- const deps = [];
195
- if (process.env.NODE_ENV === "development") {
202
+ writeGeneratedFile(filePath, content) {
203
+ fileSystem.ensureDir(path.dirname(filePath));
204
+ if (fileSystem.exists(filePath) && fileSystem.readFileSync(filePath) === content) {
205
+ return;
206
+ }
207
+ fileSystem.write(filePath, content);
196
208
  }
197
- return deps;
198
- }
199
- /**
200
- * Prepares build contributions if not already done and rehydrates previously generated image outputs.
201
- */
202
- async setup() {
203
- await this.prepareBuildContributions();
204
- await this.rehydrateGeneratedOutputs();
205
- }
206
- /**
207
- * Process images.
208
- * @param images
209
- */
210
- async process(images) {
211
- if (!this.processor) {
212
- throw new Error("ImageProcessor not initialized");
209
+ /**
210
+ * Ensures optimized image outputs and virtual-module state exist on disk.
211
+ */
212
+ async setup() {
213
+ this.initializeProcessor();
214
+ await this.ensureGeneratedOutputs();
213
215
  }
214
- logger.debug("Processing images", { count: images.length });
215
- for (const image of images) {
216
- try {
217
- const result = await this.processor.processImage(image);
218
- if (result) {
219
- this.processedImages[path.basename(image)] = result;
216
+ /**
217
+ * Process images.
218
+ * @param images
219
+ */
220
+ async process(images) {
221
+ if (!this.processor) {
222
+ throw new Error('ImageProcessor not initialized');
223
+ }
224
+ logger.debug('Processing images', { count: images.length });
225
+ for (const image of images) {
226
+ try {
227
+ const result = await this.processor.processImage(image);
228
+ if (result) {
229
+ this.processedImages[path.basename(image)] = result;
230
+ }
231
+ }
232
+ catch (error) {
233
+ logger.error('Failed to process image', { image, error });
234
+ }
220
235
  }
221
- } catch (error) {
222
- logger.error("Failed to process image", { image, error });
223
- }
236
+ this.generateTypes();
224
237
  }
225
- this.generateTypes();
226
- }
227
- /**
228
- * Delete processed images using the original image path.
229
- * @param imagePath
230
- */
231
- async deleteProcessedImagesbyPath(imagePath) {
232
- if (!this.processor) {
233
- throw new Error("ImageProcessor not initialized");
238
+ /**
239
+ * Delete processed images using the original image path.
240
+ * @param imagePath
241
+ */
242
+ async deleteProcessedImagesbyPath(imagePath) {
243
+ if (!this.processor) {
244
+ throw new Error('ImageProcessor not initialized');
245
+ }
246
+ logger.debug('Deleting processed images', { path: imagePath });
247
+ try {
248
+ const baseNameWithoutExt = path.basename(imagePath, path.extname(imagePath));
249
+ if (!this.options) {
250
+ throw new Error('Options not set');
251
+ }
252
+ const outputDir = this.options.outputDir;
253
+ const files = await fileSystem.glob([`${outputDir}/${baseNameWithoutExt}-*`]);
254
+ await Promise.all(files.map(async (file) => {
255
+ try {
256
+ await fileSystem.removeAsync(file);
257
+ logger.debug('Deleted processed image', { file });
258
+ }
259
+ catch (error) {
260
+ logger.error('Failed to delete processed image', { file, error });
261
+ }
262
+ }));
263
+ try {
264
+ const cacheKey = this.processedImages[path.basename(imagePath)].cacheKey;
265
+ const cachePath = this.getCachePath(cacheKey);
266
+ await fileSystem.removeAsync(cachePath);
267
+ logger.debug('Deleted cache file for image', { cachePath });
268
+ }
269
+ catch (error) {
270
+ logger.error('Failed to delete cache file for image', { imagePath, error });
271
+ }
272
+ delete this.processedImages[path.basename(imagePath)];
273
+ this.generateTypes();
274
+ }
275
+ catch (error) {
276
+ logger.error('Failed to delete processed images', { path: imagePath, error });
277
+ }
234
278
  }
235
- logger.debug("Deleting processed images", { path: imagePath });
236
- try {
237
- const baseNameWithoutExt = path.basename(imagePath, path.extname(imagePath));
238
- if (!this.options) {
239
- throw new Error("Options not set");
240
- }
241
- const outputDir = this.options.outputDir;
242
- const files = await fileSystem.glob([`${outputDir}/${baseNameWithoutExt}-*`]);
243
- await Promise.all(
244
- files.map(async (file) => {
245
- try {
246
- await fileSystem.removeAsync(file);
247
- logger.debug("Deleted processed image", { file });
248
- } catch (error) {
249
- logger.error("Failed to delete processed image", { file, error });
250
- }
279
+ /**
280
+ * Generate types for the virtual module.
281
+ */
282
+ generateTypes() {
283
+ this.writeVirtualModuleTypes(Object.keys(this.processedImages));
284
+ if (!this.context)
285
+ throw new Error('Processor is not configured correctly');
286
+ const runtimeVirtualModulePath = resolveGeneratedPath('cache', {
287
+ root: this.context.distDir,
288
+ module: this.name,
289
+ subPath: 'virtual-module.ts',
290
+ });
291
+ const runtimeModuleContent = Object.entries(this.processedImages)
292
+ .map(([key, value]) => {
293
+ return `export const ${anyCaseToCamelCase(key)} = ${JSON.stringify(value, null, 2)} as const;`;
251
294
  })
252
- );
253
- try {
254
- const cacheKey = this.processedImages[path.basename(imagePath)].cacheKey;
255
- const cachePath = this.getCachePath(cacheKey);
256
- await fileSystem.removeAsync(cachePath);
257
- logger.debug("Deleted cache file for image", { cachePath });
258
- } catch (error) {
259
- logger.error("Failed to delete cache file for image", { imagePath, error });
260
- }
261
- delete this.processedImages[path.basename(imagePath)];
262
- this.generateTypes();
263
- } catch (error) {
264
- logger.error("Failed to delete processed images", { path: imagePath, error });
265
- }
266
- }
267
- /**
268
- * Generate types for the virtual module.
269
- */
270
- generateTypes() {
271
- if (!this.options?.outputDir) {
272
- throw new Error("Output directory not set");
295
+ .join('\n\n');
296
+ this.writeGeneratedFile(runtimeVirtualModulePath, runtimeModuleContent);
297
+ logger.debug('Generated runtime virtual module for images', { runtimeVirtualModulePath });
273
298
  }
274
- const content = `
299
+ /**
300
+ * Writes the ambient declaration package for `ecopages:images`.
301
+ */
302
+ writeVirtualModuleTypes(imageKeys) {
303
+ const content = `
275
304
  /**
276
305
  * Do not edit manually. This file is auto-generated.
277
306
  * This file contains the type definitions for the virtual module "ecopages:images".
@@ -280,55 +309,40 @@ class ImageProcessorPlugin extends Processor {
280
309
  ${IMAGE_VIRTUAL_MODULE_TYPES}
281
310
 
282
311
  declare module "ecopages:images" {
283
- ${Object.keys(this.processedImages).map((key) => `export const ${anyCaseToCamelCase(key)}: ImageSpecifications;`).join("\n ")}
312
+ ${imageKeys.map((key) => `export const ${anyCaseToCamelCase(key)}: ImageSpecifications;`).join('\n ')}
284
313
  }`;
285
- if (!this.context) throw new Error("Processor is not configured correctly");
286
- const typesDir = resolveGeneratedPath("types", {
287
- root: this.context.rootDir,
288
- module: this.name,
289
- subPath: "virtual-module.d.ts"
290
- });
291
- fileSystem.ensureDir(path.dirname(typesDir));
292
- fileSystem.write(typesDir, content);
293
- logger.debug("Generated types for virtual module", { typesDir });
294
- const indexTypesDir = resolveGeneratedPath("types", {
295
- root: this.context.rootDir,
296
- module: this.name,
297
- subPath: "index.d.ts"
298
- });
299
- const indexContent = 'import "./virtual-module.d.js";';
300
- fileSystem.write(indexTypesDir, indexContent);
301
- logger.debug("Generated index types for virtual module", { indexTypesDir });
302
- const runtimeVirtualModulePath = resolveGeneratedPath("cache", {
303
- root: this.context.distDir,
304
- module: this.name,
305
- subPath: "virtual-module.ts"
306
- });
307
- const runtimeModuleContent = Object.entries(this.processedImages).map(([key, value]) => {
308
- return `export const ${anyCaseToCamelCase(key)} = ${JSON.stringify(value, null, 2)} as const;`;
309
- }).join("\n\n");
310
- fileSystem.ensureDir(path.dirname(runtimeVirtualModulePath));
311
- fileSystem.write(runtimeVirtualModulePath, runtimeModuleContent);
312
- logger.debug("Generated runtime virtual module for images", { runtimeVirtualModulePath });
313
- }
314
- /**
315
- * Teardown the image processor.
316
- */
317
- async teardown() {
318
- logger.debug("Tearing down image processor");
319
- }
320
- /**
321
- * Get the image processor instance.
322
- * @returns The image processor instance.
323
- */
324
- getProcessor() {
325
- return this.processor;
326
- }
314
+ if (!this.context)
315
+ throw new Error('Processor is not configured correctly');
316
+ const typesDir = resolveGeneratedPath('types', {
317
+ root: this.context.rootDir,
318
+ module: this.name,
319
+ subPath: 'virtual-module.d.ts',
320
+ });
321
+ this.writeGeneratedFile(typesDir, content);
322
+ logger.debug('Generated types for virtual module', { typesDir });
323
+ const indexTypesDir = resolveGeneratedPath('types', {
324
+ root: this.context.rootDir,
325
+ module: this.name,
326
+ subPath: 'index.d.ts',
327
+ });
328
+ const indexContent = 'import "./virtual-module.d.js";\n';
329
+ this.writeGeneratedFile(indexTypesDir, indexContent);
330
+ logger.debug('Generated index types for virtual module', { indexTypesDir });
331
+ writeGeneratedTypesPackage({
332
+ root: this.context.rootDir,
333
+ module: this.name,
334
+ packageName: '@types/ecopages-image-processor',
335
+ writeFile: (filePath, content) => this.writeGeneratedFile(filePath, content),
336
+ });
337
+ }
338
+ /**
339
+ * Get the image processor instance.
340
+ * @returns The image processor instance.
341
+ */
342
+ getProcessor() {
343
+ return this.processor;
344
+ }
327
345
  }
328
- const imageProcessorPlugin = (config) => {
329
- return new ImageProcessorPlugin(config);
330
- };
331
- export {
332
- ImageProcessorPlugin,
333
- imageProcessorPlugin
346
+ export const imageProcessorPlugin = (config) => {
347
+ return new ImageProcessorPlugin(config);
334
348
  };
package/src/types.js CHANGED
@@ -0,0 +1 @@
1
+ export {};
package/src/utils.js CHANGED
@@ -1,27 +1,26 @@
1
- function anyCaseToCamelCase(str) {
2
- if (!str) return "";
3
- let result = "";
4
- let capitalize = false;
5
- for (let i = 0; i < str.length; i++) {
6
- const char = str[i];
7
- if (/[0-9]/.test(char)) {
8
- result += char;
9
- capitalize = true;
10
- continue;
1
+ export function anyCaseToCamelCase(str) {
2
+ if (!str)
3
+ return '';
4
+ let result = '';
5
+ let capitalize = false;
6
+ for (let i = 0; i < str.length; i++) {
7
+ const char = str[i];
8
+ if (/[0-9]/.test(char)) {
9
+ result += char;
10
+ capitalize = true;
11
+ continue;
12
+ }
13
+ if (/[a-zA-Z]/.test(char)) {
14
+ if (capitalize) {
15
+ result += char.toUpperCase();
16
+ capitalize = false;
17
+ }
18
+ else {
19
+ result += char.toLowerCase();
20
+ }
21
+ continue;
22
+ }
23
+ capitalize = true;
11
24
  }
12
- if (/[a-zA-Z]/.test(char)) {
13
- if (capitalize) {
14
- result += char.toUpperCase();
15
- capitalize = false;
16
- } else {
17
- result += char.toLowerCase();
18
- }
19
- continue;
20
- }
21
- capitalize = true;
22
- }
23
- return result;
25
+ return result;
24
26
  }
25
- export {
26
- anyCaseToCamelCase
27
- };
@@ -1,22 +0,0 @@
1
- /**
2
- * This file contains the plugins for bundling the image specifications.
3
- * @module @ecopages/image-processor/bun-plugins
4
- */
5
- import type { EcoBuildPlugin } from '@ecopages/core/plugins/processor';
6
- import type { ImageMap } from './plugin.js';
7
- /**
8
- * This function creates a plugin for bundling the image specifications.
9
- * https://bun.sh/docs/runtime/plugins#virtual-modules
10
- * @param exports
11
- * @returns
12
- */
13
- export declare function createImagePlugin(exports: ImageMap): EcoBuildPlugin;
14
- /**
15
- * This function creates a plugin for bundling the image specifications.
16
- * Due to some limitations in the bundler, we need to use a different approach.
17
- * https://bun.sh/docs/runtime/plugins#virtual-modules > bun-v1.2.5
18
- * (This feature is currently only available at runtime with Bun.plugin and not yet supported in the bundler, but you can mimic the behavior using onResolve and onLoad.)
19
- * @param exports
20
- * @returns
21
- */
22
- export declare function createImagePluginBundler(exports: ImageMap): EcoBuildPlugin;