jekyll-imgflow 0.4.4 → 0.4.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9496f81e064e499eed64e5b894553a4631448bb103a1f538fa10d5d16b09028
4
- data.tar.gz: cb2c0d6d2fda26e79bbddcd2de701a626c0fde8a1b2cdd1e49116f25e05cfc72
3
+ metadata.gz: 378cd2bfd613a2de7d046e60c069d1aee35f7863b4ea3dc203dd2a5eba24d33d
4
+ data.tar.gz: 6f0dbfbfdede93e1831d405ed6b6aaf8f337f55a14187c7c11a05e7dcaf29e29
5
5
  SHA512:
6
- metadata.gz: 6cc5cd2ef513d558f2fc5fc84ed0170ec5bb6361907ce72212e8cf6138865dc9fddb59e1ec62880f41740f762bbdc550434145849d4f781ede0e1e22a031055f
7
- data.tar.gz: 2c95809a7775802e1a0a7932b1532c04bfe8d845806c0d73859096f33e1df8062717ce59244c85d46186158c1621ff093242da97f84758ca567e39134568a0ff
6
+ metadata.gz: 717eb16a4931a2b72dd2bee755711e9b867ab47ee2f49059e7cab0f3ecc67446a535ebfae427c8bc4859957e247eacb8c81b26d74a5099d9f72f154ef487c994
7
+ data.tar.gz: ca5979aa3aaa7810260227c821ce2346433723268a75487d563857bed9d977ac0c6ea79ef10d79670010fea8fd133c392a7e8c8d764f4f7a611f7f7649ccaae1
data/CHANGELOG.md ADDED
@@ -0,0 +1,609 @@
1
+ # Changelog
2
+
3
+ ## [0.4.5] - 2026-11-10
4
+
5
+ ### Added
6
+
7
+ - `rake docs:demo` — captures the checked-in illustrative overview as
8
+ animated AVIF + WebP + static PNG (headless Chrome + ffmpeg + img2webp;
9
+ build-host tools), embedded in README via `<picture>`. Examples are
10
+ schematic, not generated from a live Jekyll build.
11
+
12
+ ### Security
13
+
14
+ - `.audit-allow.json`: allowlisted two dev-only npm advisories with no
15
+ in-range fix — `glob` (GHSA-3g3m-2fjr-6pw4, patched only in 14.x while
16
+ sharp-cli pins ^13) and `minimatch` (GHSA-g3hv-75wg-m249, patched only
17
+ in 11.x while consumers pin ^10), both expiring 2027-02-09. Dev tooling
18
+ only — the gem is pure Ruby.
19
+
20
+ ### Changed
21
+
22
+ - Gemspec description rewritten in RDoc markup (`==` heading at column 0)
23
+ so rubygems.org renders it as structured markup instead of a single
24
+ paragraph, and now mentions the jekyll-imgflow-vscode companion
25
+ extension.
26
+ - Gemspec metadata links completed: `homepage_uri`, `source_code_uri`,
27
+ `changelog_uri`, and `bug_tracker_uri` for the rubygems.org link panel.
28
+ - `CHANGELOG.md` added to `spec.files` so it ships inside the packaged gem.
29
+ - `jekyll` runtime dependency now bounded `< 5.0` (was unbounded `>= 4.0`).
30
+
31
+ - **Docker test service lifecycle** — service-dependent rake tasks
32
+ (`test_http_providers`, `test_jekyll`, `test_picture`, `test_integration`,
33
+ `test_comprehensive`, `test_all`, `performance_benchmark`, `parallel:slow`)
34
+ now start the Docker test services automatically if they are not running
35
+ and always stop them when the run finishes (pass or fail). Containers no
36
+ longer linger after test runs or pre-push. `start_services`/`stop_services`
37
+ remain for keeping services up across repeated test runs.
38
+ - **Docker daemon auto-start** — `start_docker_services` now launches Docker
39
+ Desktop on macOS when the daemon is down, waiting up to
40
+ `DOCKER_DAEMON_TIMEOUT` (default 120s); on other platforms it aborts with a
41
+ clear message instead of a cryptic `docker-compose` failure. The pre-push
42
+ hook prints the last 20 lines of the HTTP provider lanes on failure instead
43
+ of discarding the output.
44
+ - **Test containers no longer restart automatically** — `docker-compose.test.yml`
45
+ overrides the `restart: unless-stopped` policy inherited from
46
+ `docker-compose.base.yml` with `restart: "no"`, so test containers no longer
47
+ survive Docker daemon or host restarts. The production compose file keeps
48
+ `restart: unless-stopped`.
49
+ - Dev-tooling bump: `webmock` `~> 3.30.0` → `~> 3.34.0` (test-only gem).
50
+
51
+ - CI: Semgrep moved from an inline `pip3 install semgrep==1.177.0` pin to hashed `.github/requirements-ci.txt` (compiled from `requirements-ci.in`, Python 3.12), installed with `--require-hashes`. Bumped Semgrep to 1.180.0. Added `.github/dependabot.yml` covering github-actions, bundler, npm, and the new `/.github` pip requirements.
52
+
53
+ ### Dependency updates
54
+
55
+ - Ruby: `rubocop` 1.92.0 → 1.92.2 (patch).
56
+ - npm: `markdownlint-cli2` 0.23.3 → 0.24.0; added `re2js` `^2.9.1`
57
+ override to fix GHSA-gg6h-894w-4m9c (ReDoS in lookbehind matching,
58
+ transitive via markdownlint ≥ 0.42.0).
59
+ - GitHub Actions: `SonarSource/sonarqube-scan-action` v8.3.0 → v8.4.0;
60
+ `DavidAnson/markdownlint-cli2-action` v24.2.0 → v25.0.0;
61
+ Semgrep container 1.182.0 → 1.183.0.
62
+ - Docker image pins: `flyimg/flyimg` 1.12.6 → 1.12.12 → 1.12.13;
63
+ `ghcr.io/imgproxy/imgproxy` v4.0.14 → v4.0.20.
64
+ `docs/docker.md` image table updated to match.
65
+ - Gem updates: `fastimage` 2.4.1 → 2.4.3, `sass-embedded` 1.105.1 → 1.107.1,
66
+ `addressable` 2.9.0 → 2.9.2, `csv` 3.3.6 → 3.3.7, `io-console` 0.9.4 → 0.9.5,
67
+ `mime-types-data` → 3.2026.1027, `parallel_tests` 5.8.0 → 5.9.0.
68
+ - Gem updates: `sass-embedded` 1.107.1 → 1.108.1, `irb` 1.18.0 → 1.19.0,
69
+ `mime-types-data` → 3.2026.1103, `rspec-*` 3.13.x patches;
70
+ `BUNDLED WITH` 2.7.2 → 4.0.24.
71
+ - GitHub Actions: `ruby/setup-ruby` v1.335.0 → v1.338.0.
72
+
73
+ ## [0.4.4] - 2026-11-07
74
+
75
+ ### Added
76
+
77
+ - **Intrinsic `width`/`height` on `<img>`** — the emitted `<img>` (and the
78
+ `<picture>` fallback) now carries the generated file's pixel dimensions,
79
+ read via `FastImage`, so browsers reserve the correct aspect-ratio box
80
+ before download. Fixes layout shift (CLS) / Lighthouse "unsized images".
81
+ User-supplied `img-width:`/`img-height:` always win; dimensions are
82
+ skipped when the file can't be read. Implemented in a new
83
+ `JekyllImgFlow::IntrinsicDimensions` module included by `HtmlGenerator`.
84
+
85
+ ## [0.4.3] - 2026-10-06
86
+
87
+ ### Security
88
+
89
+ - `sharp` forced to 0.35.5 via npm `overrides` — sharp-cli 6.1.0 pins
90
+ exactly 0.35.4, which the audit gate flags for a use-after-free in
91
+ bundled librsvg (GHSA-wq5f-xc86-pv6w / CVE-2026-96889). The override
92
+ ships libvips with the patched librsvg 2.63.2; remove it once
93
+ sharp-cli bumps its pin. Dev tooling only — the gem is pure Ruby.
94
+
95
+ ### Added
96
+
97
+ - `rake test_http_providers` — runs `provider_meta_testing_spec.rb` once per
98
+ HTTP provider (`IMGFLOW_TEST_PROVIDER` lane: imgproxy, weserv, flyimg),
99
+ giving each its WEBrick source server reachable via host.docker.internal.
100
+ Wired into the local pre-push hook (services auto-start if down); kept out
101
+ of GitHub CI to save runner resources. Without the env var the aggregate
102
+ suite only exercised CLI providers end-to-end.
103
+
104
+ ### Changed
105
+
106
+ - flyimg test image pin bumped 1.12.5 to 1.12.6.
107
+
108
+ ## [0.4.2] - 2026-10-06
109
+
110
+ ### Security
111
+
112
+ - Dev-tooling audit gate: `scripts/npm-audit.mjs` + `.audit-allow.json`
113
+ wired as the `audit` npm script — patchable transitive deps forced via
114
+ `overrides` (smol-toml 1.9.0, katex 0.18.2); the unpatched braces
115
+ advisory is allowlisted with reason + expiry (dev-only linting).
116
+ - Rakefile `ci` markdownlint pin corrected 0.23.2 to 0.23.3 (matches
117
+ `package.json`).
118
+
119
+ ### Added
120
+
121
+ - `JekyllImgFlow::Interface.to_h` — the public `{% imgflow %}` surface
122
+ (operation params, HTML attributes, `markup:` formats, config keys)
123
+ derived from `Parser`/`HtmlGenerator`/`Configuration` constants,
124
+ serialized to a committed `interface.yml` by `rake interface` for
125
+ downstream tooling (e.g. the jekyll-imgflow-vscode parity spec).
126
+ - `spec/interface_spec.rb` pins code ↔ manifest ↔ docs: a stale
127
+ `interface.yml` or undocumented declared item fails the suite.
128
+ - `docs/usage/tag-options.md` — the complete `{% imgflow %}` parameter
129
+ reference (operations, HTML attributes including `link:`/`modal:`, and
130
+ `markup:` output formats); linked from the README docs index and from
131
+ the provider-interface page that previously looked like tag docs.
132
+
133
+ ### Changed
134
+
135
+ - The `:site, :post_write` manifest hook is explicitly `priority: :normal`
136
+ (20) — ordinary post-write transforms run first, then
137
+ jekyll-fingerprint-flow (default 12), then jekyll-compress-flow (default
138
+ 10) generates compressed siblings from the final fingerprinted HTML.
139
+ - `.ruby-version` is now the single source for the Ruby version: the
140
+ Gemfile reads it directly and the gemspec derives
141
+ `required_ruby_version` from it, joining CI which already did.
142
+ - Added `rake version:check_consistency` (flags Ruby literals that
143
+ drift from `.ruby-version`, including `.rubocop.yml`'s
144
+ `TargetRubyVersion`) and `rake version:pre_release`, which runs it
145
+ together with `version:check_changelog` before tagging.
146
+ - Removed the stale "980 examples" test count from agent steering
147
+ files — counts that change on their own shouldn't be restated.
148
+
149
+ ### Fixed
150
+
151
+ - `markup:` was parsed into `raw_options` but never surfaced as
152
+ `markup_format`, so `{% imgflow x.jpg markup:direct_url %}` silently
153
+ rendered the default markup. The parser now maps `markup:`/
154
+ `markup_format:` through, covered by end-to-end tag specs. An explicit
155
+ `markup:` also takes precedence over the automatic `<picture>` upgrade
156
+ for multi-format output.
157
+ - Moved git hooks into `bin/hooks/` as tracked files and switched
158
+ `bin/install-hooks.sh` to set `core.hooksPath` instead of generating
159
+ copies into `.git/hooks/` — the generated `pre-commit` (with
160
+ `semgrep --pro`) had drifted from the installed hook (without it).
161
+ - Corrected hook documentation: `pre-commit` has always run RuboCop +
162
+ Semgrep, not RuboCop alone (AGENTS.md, docs/development.md,
163
+ docs/scripts.md).
164
+
165
+ ## [0.4.1] - 2026-09-18
166
+
167
+ ### Added
168
+
169
+ - Added Codecov coverage reporting: CI uploads Cobertura XML (via
170
+ `simplecov-cobertura`) after the test suite, with `codecov.yml` status
171
+ checks tracking project and patch coverage.
172
+ - Added SonarCloud quality gate badge to the README.
173
+
174
+ ### Changed
175
+
176
+ - Decomposed CodeFactor-flagged complex methods into focused helpers:
177
+ `crop_coords`/`relative_file_path` extracted in `BaseProvider`,
178
+ `prepare_manifest`/`queue_default_tasks`/`queue_tasks_for`/
179
+ `find_default_version` in `BuildTimeProcessor`, per-operation merge
180
+ helpers in `PresetManager`, `matching_variant_path` in `ModalAssets`,
181
+ `build_resize_data` in `ResizeTag`, status/count helpers in
182
+ `TestLogger`, `print_result_counts`/`print_individual_results` in
183
+ `ParallelProviderRunner`, and discovery/validation/output-info helpers
184
+ in `provider_test_helper.rb`, `provider_capabilities_spec.rb`, and
185
+ `TestEnvironment.site_url`.
186
+ - `Config#assign_core_config` now iterates a `CORE_CONFIG_DEFAULTS`
187
+ key→default map instead of repeating `@x = cfg[...] || DEFAULT` lines.
188
+
189
+ ### Fixed
190
+
191
+ - Resolved SonarQube analysis findings: pinned `semgrep==1.177.0` with
192
+ `--only-binary :all:` in CI, replaced `[` with `[[` in
193
+ `scripts/run_tests.sh`, and replaced raw `ENV[...]` access with
194
+ `ENV.fetch` defaults in `spec/spec_helper.rb` and
195
+ `spec/support/test_pictures.rb`.
196
+ - `TestLogger.show_status` was unreachable — `def self.` inside
197
+ `class << self` defined it on the singleton-of-singleton, so
198
+ `rake test_status` and `scripts/run_tests.sh status` raised
199
+ `NoMethodError`. The status methods are now regular public class
200
+ methods.
201
+ - `ProviderTestHelper.print_summary` computed a provider summary but
202
+ discarded it; it now logs the summary via `Jekyll.logger`.
203
+ - `ProviderTestHelper.test_single_provider` referenced an undefined
204
+ `context` variable that only worked by accident through RSpec's
205
+ top-level DSL; the caller's context is now passed through explicitly.
206
+
207
+ ## [0.4.0] - 2026-09-12
208
+
209
+ ### Changed
210
+
211
+ - Extracted shared provider behavior into `BaseProvider` helpers
212
+ (`find_op`, `op?`, `crop_geometry`, `watermark_parts`, `compass_to_short`,
213
+ `input_format_ext`) to eliminate duplicated operation lookups, crop
214
+ parsing, watermark extraction, and compass-position translation across all
215
+ six providers.
216
+ - Introduced `Providers::HttpBase < BaseProvider` to centralize HTTP-provider
217
+ availability checks, request execution, fetching with timeout, and error
218
+ handling. `imgproxy`, `weserv`, and `flyimg` now inherit this scaffolding
219
+ and only provide their service URL and URL-building logic.
220
+ - Introduced `Providers::CliBase < BaseProvider` to centralize the shared
221
+ CLI-provider `execute` skeleton (empty-operations guard, build, run,
222
+ reset). `sharp`, `imagemagick`, and `libvips` now inherit it and only
223
+ provide `build_commands` and optional `before_execute`/`run_command`
224
+ overrides.
225
+ - Added `cli_available?(*commands)`, `temp_path(input_path, suffix)`,
226
+ `alpha_byte_value(opacity)`, and `smartcrop_interestingness(keep)`
227
+ helpers to `BaseProvider`, eliminating repeated `Open3.capture3("which",
228
+ …)` calls, temp-file path `gsub` patterns, `* 255).round` calculations,
229
+ and smartcrop interestingness mappings across all six providers.
230
+ - Moved duplicated `validate_quality`, `valid_numeric?`, and
231
+ `validate_opacity` methods from individual tag classes into `BaseTag`.
232
+ `validate_opacity` is now parameterized by `min:`/`max:` so both
233
+ `OpacityTag` (0.01–0.99) and `WatermarkTag` (0.0–1.0) share one
234
+ implementation.
235
+ - Consolidated `CropTag#get_original_dimensions` into `BaseTag` as a
236
+ raising variant of the existing `get_image_dimensions` helper.
237
+ - Refactored `sharp`, `imagemagick`, and `libvips` to use the shared
238
+ `crop_geometry`, `watermark_parts`, and `op?` helpers, removing the
239
+ repeated crop-parsing block and operation lookups.
240
+ - Removed no-op `translate_quality_to_*` methods from the HTTP providers;
241
+ they returned the input quality unchanged.
242
+ - Decomposed `Parser.detect_operations`, `PresetManager.yaml_to_tags`,
243
+ `TagScanner#parse_tag_markup_simple`, `PictureTagPresetMigrator`
244
+ conversion/description, `CropTag#process`, and `ResizeTag#process` into
245
+ smaller focused helper methods without changing behavior.
246
+
247
+ ### Fixed
248
+
249
+ - Weserv provider now handles SVG files without explicit pixel dimensions
250
+ (e.g. `width="100%"` with a large `viewBox`). When no resize or crop
251
+ operation is present, a default `w=2000` parameter is added so librsvg
252
+ rasterizes at a reasonable size instead of the full viewBox dimensions
253
+ (which could exceed 85 megapixels and cause memory exhaustion or
254
+ connection drops).
255
+ - Removed the duplicate `show_status` definition in `scripts/test_logger.rb`
256
+ that shadowed the canonical implementation in `class << self`.
257
+
258
+ ## [0.3.3] - 2026-09-11
259
+
260
+ ### Added
261
+
262
+ - Added Semgrep and CodeFactor status badges to the README.
263
+ - Documented local Semgrep Pro scans and `semgrep ci` dashboard
264
+ synchronization. GitHub Actions continues to publish CI findings through
265
+ `SEMGREP_APP_TOKEN`, while CodeFactor analyzes the repository through its
266
+ GitHub integration.
267
+
268
+ ### Fixed
269
+
270
+ - Replaced shell-interpolated cleanup and test-helper commands with argument
271
+ arrays and process APIs where possible.
272
+ - Added explicit Semgrep suppressions for intentional Jekyll Picture Tag MD5
273
+ compatibility hashes and provider commands that use safe argument arrays or
274
+ shell-escaped paths.
275
+ - Refactored complex test helpers, performance-report helpers, configuration,
276
+ Picture Tag translation, manifest registration, provider pipelines, and
277
+ ImgFlow operation processing without changing behavior.
278
+ - Corrected chained collection-method alignment and shell argument display in
279
+ test utilities.
280
+ - Prevented unchanged rebuilds from persisting the transient manifest state
281
+ created while specialized page usage is reset, keeping the final manifest
282
+ timestamp stable when its content is unchanged.
283
+ - Increased the Flyimg request timeout for large PNG/TIFF processing and
284
+ reduced default slow-test concurrency to avoid exhausting local Docker
285
+ resources during comprehensive provider runs.
286
+
287
+ ### Changed
288
+
289
+ - Updated the checked-in performance benchmark report and JSON results from the
290
+ full local provider test run.
291
+
292
+ ### Security
293
+
294
+ - Pinned all GitHub Actions used by CI and release workflows to immutable
295
+ commit SHAs to prevent mutable-tag supply-chain changes.
296
+
297
+ ## [0.3.2] - 2026-09-09
298
+
299
+ ### Fixed
300
+
301
+ - **Modal full-size variants** — modal links now generate optimized variants at
302
+ the smaller of the original image width and configured maximum size, avoiding
303
+ upscaled 2000px outputs for originals such as 1680px images.
304
+ - **Modal format negotiation** — the modal now opens a `<picture>` element with
305
+ AVIF/WebP/PNG sources and the configured fallback format, instead of always
306
+ loading the fallback file directly.
307
+
308
+ ### Added
309
+
310
+ - Regression coverage for original-width modal generation and optimized modal
311
+ format selection.
312
+
313
+ ## [0.3.1] - 2026-09-09
314
+
315
+ ### Fixed
316
+
317
+ - **Sharp CLI format compatibility** — the Sharp provider now translates
318
+ ImgFlow's public `jpg` format name to Sharp CLI's required `jpeg` argument,
319
+ preserving `.jpg` output filenames while supporting Sharp CLI 6.x.
320
+
321
+ ### Changed
322
+
323
+ - Development and CI tooling now pins Sharp CLI to `6.1.0`, with Dependabot
324
+ coverage for the npm development dependency tree.
325
+ - CI and local development now share the committed Ruby version from
326
+ `.ruby-version`; `rake ci` mirrors the GitHub Actions checks and runs
327
+ automatically from the pre-push hook.
328
+ - CI uses Ubuntu 26.04 with the required libvips/ImageMagick and AVIF codec
329
+ packages, while Docker-backed HTTP provider tests remain local-only.
330
+
331
+ ### Security
332
+
333
+ - Fixed incomplete escaping of backslashes in preset image paths.
334
+ - Replaced the Picture Tag adaptor's backtracking regex with indexed parsing to
335
+ remove the CodeQL polynomial-ReDoS finding.
336
+
337
+ ## [0.3.0] - 2026-09-09
338
+
339
+ ### Added
340
+
341
+ - **Image modal/lightbox by default** — clicking an `{% imgflow %}` image now opens a full-size modal popup showing the largest generated version. The modal is enabled by default (`image_modal: true` in config) and requires no user setup — CSS and JS are automatically injected into pages that contain modal-enabled images via a `post_render` hook. Disable globally in `_config.yml` with `image_modal: false`. Per-image overrides: `modal:true` forces the modal on (even when config is `false`), `modal:false` forces it off. Images with an explicit `link:` attribute use that link instead (modal is skipped). The modal supports keyboard navigation (Escape to close) and click-outside-to-close.
342
+
343
+ ## [0.2.0] - 2026-09-08
344
+
345
+ ### Fixed
346
+
347
+ - **Specialized and default versions only produced a single format** — `{% imgflow %}` tags without an explicit `format:`/`formats:` parameter generated only one output file (falling back to the original extension, e.g. `.jpg`) and rendered a simple `<img>` tag instead of a `<picture>` element. `process_variants` now expands to all configured formats (`avif`, `webp`, `png`, `jpg`) when no format is specified, so both default-width and specialized versions produce a `<picture>` with `<source>` tags for modern formats and an `<img>` fallback. Explicit `format:` and `formats:` selections (e.g. `format:avif`, `formats:avif,png`, `formats:webp,jpg`) are respected for both default and specialized widths.
348
+
349
+ ### Added
350
+
351
+ - Unit and integration tests verifying explicit format selection: single format (`format:avif`), multiple formats (`formats:avif,png`, `formats:webp,jpg`), and no-format expansion for both default and specialized widths.
352
+ - Tests verifying format config change lifecycle: obsolete default format files are deleted when formats shrink (e.g. `avif,webp,png,jpg` → `avif,png`), missing formats are detected for regeneration when formats grow (e.g. `avif,png` → `avif,png,jpg`), and specialized versions are preserved during default cleanup.
353
+
354
+ ## [0.1.11] - 2026-09-07
355
+
356
+ ### Added
357
+
358
+ - Rake task `check_docker_images` queries upstream registries (GHCR, Docker Hub) for the latest version tags and compares against the pins in `docker-compose.base.yml`. Use `STRICT=true` to fail the task when any pin is outdated — run before releasing.
359
+ - Rake tasks `start_services` and `stop_services` for starting and stopping test Docker services. `start_services` pulls the latest pinned images before starting containers.
360
+ - Pre-push git hook now runs `check_docker_images` when pushing a `v*` tag, blocking releases with stale Docker image pins.
361
+ - Release workflow (`release.yml`) now verifies Docker image pins are current before building and publishing the gem.
362
+ - Rake tasks `imgflow:presets` and `imgflow:install_presets` for listing and installing built-in YAML presets in consuming sites that load `jekyll-imgflow/tasks` from their Rakefile.
363
+ - Built-in YAML presets `gallery`, `hero`, and `thumbnail` shipped under `lib/jekyll-imgflow/presets/`; user presets in `_data/imgflow/presets/*.yml` override built-ins.
364
+ - `{% imgflow ... preset:NAME %}` tags now expand YAML presets through `PresetManager`, with user tag values overriding preset values and multi-format presets rendering `<picture>` sources plus a fallback image.
365
+ - Rake task `parallel:slow` runs slow tests in parallel using a dynamic work queue across providers, cross-provider comparisons, manifest changes, error handling, and performance benchmarks, utilizing available CPU cores.
366
+ - `TestEnvironment` module (`spec/support/test_environment.rb`) centralizes provider lists, port allocation, and test configuration previously inlined in `spec_helper.rb`, eliminating duplicated constants and port-collision bugs in parallel test runs.
367
+ - `spec/support/provider_integration_helper.rb` extracted shared provider integration test setup (prebuilt sites, server lifecycle, fixture selection) from `spec_helper.rb`.
368
+ - `spec/docker_service_status_spec.rb` adds 23 unit tests for `DockerServiceStatus` covering service path mapping, readiness/failed state detection, compose record parsing (single/array/newline-delimited/invalid JSON), HTTP status (200/503/connection refused/EOF/timeout), container status, and wait/timeout behavior.
369
+
370
+ ### Fixed
371
+
372
+ - **Manifest wiped on every server restart** — the manifest now persists under the configured `cache_dir` instead of `_site/`, so Jekyll destination cleanup cannot remove it. The cache directory is excluded from Jekyll watch processing, unchanged manifests are not rewritten, and updates use an atomic temporary-file rename.
373
+ - **Persisted operation comparison** — manifest operations are recursively normalized after JSON persistence, preventing duplicate versions when in-memory symbol keys or values are compared with persisted strings.
374
+ - **Unwritten `.cache_key` dependency** — cache checks no longer require sidecar files that no code path created. Every generated version stores the SHA-256 digest of its source bytes, so changed content is regenerated even when `mtime` is preserved, while timestamp-only changes remain cached.
375
+ - **Incomplete cache checks** — every configured default size/format/quality combination must have a matching manifest entry, current provider, current source digest, and existing output file before an original is skipped. Missing default or specialized outputs and newly configured defaults are regenerated.
376
+ - **Stale generated files** — deleted originals now remove their default and specialized outputs from both source and destination. Defaults removed from configured sizes/formats are pruned with path-safe deletion and empty-directory cleanup.
377
+ - **Deleted-original matching** — cleanup compares complete paths relative to the originals directory instead of extensionless basenames. Animated GIFs remain part of discovery and are no longer mistaken for deleted originals when default conversion is skipped.
378
+ - **Specialized orphan cleanup** — specialized page usage is reset before rendering, rebuilt by rendered tags, cleaned in non-development builds, and saved through the shared manifest.
379
+ - **Double registration** — processed versions remain registered by `OperationProcessor`; only existing outputs skipped while rebuilding a missing manifest are registered by `BuildTimeProcessor`.
380
+ - **Deep permalink and `baseurl` paths** — generated `<img>` and `<source>` paths are root-absolute and include Jekyll's configured `baseurl` without duplicating it. Absolute URLs use the same normalized path.
381
+ - **Stale watch components** — each build refreshes the shared config, manifest, provider, and processor used by Liquid tags, allowing new originals and changed tag operations to use current state.
382
+ - **Legacy manifest migration (v0.1.10 → v0.1.11)** — manifests from v0.1.10 stored operations without `format`/`quality` and had no `file_digest`. These entries are now detected and cleared on load so existing optimized files are re-registered from disk without reprocessing.
383
+ - **Unnecessary reprocessing on render** — `OperationProcessor#process_operation` now checks if the output file already exists and is up-to-date before invoking the provider, preventing redundant Sharp/ImageMagick calls when the manifest is out of sync.
384
+ - **ReDoS in Picture Tag adaptor** — the `{% picture ... %}` extraction regex no longer has polynomial backtracking from redundant `\s*` before `%}`.
385
+ - **ReDoS in opacity validation** — `OpacityTag` and `WatermarkTag` replaced the `\A\d*\.?\d+\z` regex with `Float()` + rescue, eliminating polynomial backtracking on malformed input.
386
+ - **Shell injection in Libvips provider** — all `build_*` methods now return command arrays executed via `Open3.capture3(*array)` (no shell). Chained `&&` commands run as separate Ruby steps, `$(vips header ...)` substitutions are pre-computed in Ruby, and `rm -f` cleanup uses `FileUtils.rm_f`.
387
+ - `preset_manager` is now initialized in `site.imgflow_components` for both `BuildTimeProcessor` and `ImgflowTag`, fixing `undefined method 'build_markup_from_preset' for nil` errors.
388
+ - Preset tag expansion now uses `Shellwords` to correctly parse quoted image paths and preserves quoted option values containing spaces or Danish characters.
389
+ - `BuildTimeProcessor` no longer resets specialized-image `used_on` metadata during incremental builds, preventing deletion of images still used by unrendered pages.
390
+ - `post_write` hook now runs specialized-image cleanup only in non-development, non-incremental builds and saves the manifest afterward.
391
+ - `ImgflowTag` now checks both manifest existence and the actual output file on disk before reusing a version.
392
+ - Default-version up-to-date checks now use source SHA-256 digests and verify the output file exists, regenerating missing or stale versions.
393
+ - **SVG processing with libvips** — the libvips provider now uses `vips thumbnail` (the recommended high-level resize API) instead of `vips VipsResize` for all resize operations. `thumbnail` bounds the SVG render size during load, preventing "image too large" errors on SVGs with large viewBoxes (e.g. 10000x8500). This also improves JPEG performance via shrink-on-load. SVG crop operations use `thumbnail --crop` to avoid coordinate mismatches.
394
+ - **SVG processing with ImageMagick** — the ImageMagick provider now sets `-density` before SVG input files, telling the rsvg delegate to rasterize at a reasonable resolution instead of the full viewBox (10000x8500 = 85M pixels). This gives ~5x speedup (10s → 2s per conversion) with no quality loss since the image is resized afterward. A warning is logged on the first SVG conversion: if the rsvg delegate is not installed, users are advised to install `librsvg` (macOS: `brew install librsvg`, Ubuntu: `apt install librsvg2-bin`) or use a different provider (sharp/libvips) for SVGs.
395
+ - **SVG output filename** — `FilenameGenerator` no longer produces `.svg` as an output format. SVG is a vector input format; image providers always produce raster output. When no format is specified for a specialized version, SVG inputs now fall back to `jpg` (the universal `<img>` fallback).
396
+ - **Nil provider crash** — `ProviderRegistry#current_provider` now logs a single centralized warning when no provider is available and returns `nil` instead of raising, eliminating duplicated warning messages in `BuildTimeProcessor` and `ImgflowTag`. Callers check for `nil` and degrade gracefully (rendering the original image without optimization).
397
+ - **Unknown operation capability check** — `BaseProvider.supports_operation?` now returns `false` for operations not in the `KNOWN_OPERATIONS` whitelist, preventing providers from claiming support for unrecognized operation types.
398
+ - **Provider operation accumulation on failure** — all six providers (`sharp`, `libvips`, `imagemagick`, `imgproxy`, `weserv`, `flyimg`) now reset their operation queue in an `ensure` block. Previously `reset_operations` ran after the provider call, so if the call raised (e.g. an HTTP timeout), operations accumulated across invocations, producing malformed Weserv/Imgproxy/Flyimg URLs with duplicated parameters (`&w=400...&w=800...&output=jpg...&output=avif`) that returned empty responses.
399
+ - **Weserv `/dev/shm` exhaustion** — the Weserv nginx proxy_cache stores up to 250MB in `/dev/shm`, but the Docker default 64MB `/dev/shm` filled during bulk test processing, causing `No space left on device` errors that returned empty responses (`EOFError`). The test container now sets `shm_size: 512mb`.
400
+ - **Weserv nginx directive duplication on restart** — the startup `sed` command appended `weserv_limit_input_pixels` on every container restart, eventually triggering `nginx: [emerg] "weserv_limit_input_pixels" directive is duplicate`. The command now deletes any existing directive before inserting exactly one.
401
+ - **Weserv read timeout** — `Weserv::TIMEOUT` increased from 10 to 30 seconds. The 10s `read_timeout` was too tight under heavy load, causing `EOFError` when the server closed the connection before the response body was fully read.
402
+ - **Docker service startup reliability** — `start_services` now uses `docker compose up -d --pull missing --force-recreate --remove-orphans` instead of an unconditional `docker-compose pull` followed by `up -d`. This avoids redundant image pulls, recreates stale containers that reference removed networks, and removes orphaned containers. On failure, recent container logs are dumped automatically. `stop_services` now passes `--remove-orphans` to clean up stale containers on shutdown.
403
+ - **Docker status helper HTTP rescue** — `DockerServiceStatus.http_status` now rescues `StandardError` instead of a narrow list, catching `EOFError`/`IOError` that occur when a service closes the connection during startup (previously crashed `start_services` with `EOFError: end of file reached`).
404
+
405
+ ### Changed
406
+
407
+ - Pinned Docker image tags in `docker-compose.base.yml` for reproducible builds: imgproxy moved from `darthsim/imgproxy:latest` (deprecated Docker Hub location) to `ghcr.io/imgproxy/imgproxy:v4.0.14`; flyimg pinned from `:latest` to `:1.12.5`. Weserv remains on `ghcr.io/weserv/images:5.x` (upstream-recommended branch tag).
408
+ - Removed broken `image_compressor` service from `docker-compose.yml` (had no `image:` key, could never start; no provider implementation existed).
409
+ - Removed dead `image_compressor_url` config plumbing from `Config`, `test_config.rb`, and `parallel_provider_test_helper.rb` — no provider ever consumed it.
410
+ - `docs/docker.md` and `docs/rake.md` updated to reflect new image tags and removed ImageCompressor references.
411
+ - Release process in `AGENTS.md` now starts with `rake check_docker_images` to verify image pins are current before releasing.
412
+ - The manifest is cache metadata and is no longer published into `_site`; legacy source and destination manifests migrate automatically to `cache_dir` and are removed after a successful save.
413
+ - Manifest operation hashes are stored in canonical JSON-compatible form.
414
+ - Generated file cleanup extracted into `GeneratedFileCleaner` for path-safe deletion from both source and destination.
415
+ - `.gitignore` excludes `.cache/imgflow/`; `docs/installation.md` and `docs/ARCHITECTURE.md` document the `cache_dir` option and updated manifest location.
416
+ - Replaced `push_gem.yml` with `release.yml` using official trusted publishing pattern (`rubygems/release-gem@v1`)
417
+ - Removed `continue-on-error: true` from CI workflow so tests and style actually gate
418
+ - Added `rake version:show`, `rake version:bump`, and `rake version:check_changelog` tasks
419
+ - Added CHANGELOG gate to release workflow (fails if entry missing for the version)
420
+ - Dropped reek from Gemfile, gemspec, Rakefile, and deleted `.reek.yml` (KISS)
421
+ - Deleted `bump_version.sh` and `release.sh` — replaced by rake tasks and release workflow
422
+ - Added `bin/install-hooks.sh` for pre-commit (rubocop) and pre-push (rubocop + rspec) hooks
423
+ - Removed dead code: `FilenameGenerator#generate_cache_key` (orphaned by the digest-based cache rewrite), unused `require "shellwords"` in libvips (orphaned by the shell-injection fix), unused `require "English"` in base_provider, and the unused `MARKUP_FORMATS` constant in `HtmlGenerator`.
424
+ - Added `benchmark ~> 0.5.0` as a runtime dependency because processing metrics require it and Ruby warns it will no longer be a default gem in Ruby 4.0.
425
+ - Updated development dependencies: `rubocop` 1.89 → 1.90, `simplecov` 1.1 → 1.2, `parallel` 2.1 → 2.2, `webmock` 3.26.2 → 3.26.4; transitive updates for `commonmarker`, `google-protobuf`, `rbs`, `ruby-lsp`, `sass-embedded`. Remaining outdated gems (`liquid`, `rouge`, `terminal-table`, `unicode-display_width`, `objective_elements`, `diff-lcs`, `json`) are blocked by Jekyll 4.x dependency constraints.
426
+ - Gemspec `icon_uri` updated from `v0.1.10` to `v0.1.11`; gemspec description now lists all six providers; `.DS_Store` files excluded from the packaged gem.
427
+ - README and docs updated: Docker service ports corrected to the new `.env.test` allocation (4022/4026/4030), `cache_dir` and preset usage documented, `parallel:slow` description corrected to reflect the dynamic work queue.
428
+ - **Gemfile/gemspec DRY refactor** — development dependencies are now declared only in the `Gemfile`, not duplicated in the gemspec. The Gemfile uses the `gemspec` directive to pull in runtime dependencies automatically, eliminating version drift between the two files. The gemspec retains only runtime dependencies (`benchmark`, `fastimage`, `jekyll`) and metadata. This follows the [rubygems guide](https://github.com/rubygems/guides/blob/main/gemfile-and-gemspec.md) best practice: runtime deps in gemspec (wide constraints), dev deps in Gemfile (tight constraints, groups, `require: false`).
429
+ - `docs/development.md` updated: release process rewritten to reflect the rake-task/GitHub-Actions workflow (was still describing deleted shell scripts); "Adding Dependencies" section documents the Gemfile/gemspec split; configuration files section describes the new `gemspec` directive pattern.
430
+ - `docs/installation.md` updated: publishing section rewritten to describe the trusted-publishing workflow instead of manual `gem push`; development installation section updated with current version and `gemspec` directive note; stale `0.1.0` version references updated to `0.1.11`.
431
+ - **Documentation DRY consolidation** — eliminated content duplication across docs to prevent drift:
432
+ - Deleted stale `docs/template/{tags,presets,preset-examples}.md` (the template→usage copy system was unmaintained; `presets.md` template documented an obsolete `_IF*.html` mechanism). Removed the `rake generate_docs` task and all references to it.
433
+ - Rewrote `docs/development.md` to link to canonical sources instead of duplicating rake tasks (3×), Docker commands (3×), testing commands (2×), the file tree (duplicates ARCHITECTURE.md), and the release process (duplicates AGENTS.md). Reduced from 297 to 118 lines.
434
+ - Rewrote `docs/README.md` as a lean documentation index — removed duplicated quick-reference blocks, key files list, and architecture summary. Links to canonical docs instead.
435
+ - Trimmed `docs/installation.md`: backend priority list now links to `providers.md` instead of duplicating benchmark numbers; publishing section links to `AGENTS.md` instead of duplicating the release procedure.
436
+ - Trimmed `README.md`: removed duplicated benchmark table (links to `providers.md`); consolidated the two config blocks into one.
437
+ - Trimmed `docs/ARCHITECTURE.md`: config example replaced with a pointer to `installation.md`; fixed `picture_tag_adapter.rb` → `picture_tag_adaptor.rb` spelling.
438
+ - Trimmed `docs/scripts.md`: removed duplicated rake task listing (links to `rake.md`).
439
+ - Fixed broken links: `PARALLEL_TESTING.md` → `parallel_testing.md` in `docs/testing.md`.
440
+ - **Performance benchmark metrics** — added `ProcessingStats` class (`lib/jekyll-imgflow/processing_stats.rb`) that tracks build-level cache hit/miss counts, wall-clock timing grouped by primary operation, and compression ratios per format. The benchmark now compares clean and cached builds for every provider and reports cache performance, operation timing, and compression ratios in JSON and markdown. Deleted `docs/PERFORMANCE_BENCHMARK_ARCHITECTURE.md` after implementing the relevant enhancements; parallel processing metrics were removed because production processing remains sequential.
441
+
442
+ ## [0.1.10] - 2026-08-18
443
+
444
+ ### Added
445
+
446
+ - **Project branding assets** — moved the full logo and icon to `docs/assets/images/` with project-specific names for GitHub documentation and the next RubyGems release.
447
+ - README branding now uses the repository logo, and the gemspec defines a stable `icon_uri` for the `0.1.10` release.
448
+
449
+ ### Fixed
450
+
451
+ - Release script now stages tracked changes only, preventing unrelated untracked files from being included in a release commit.
452
+ - Version bumping now synchronizes `Gemfile.lock` and carries `[Unreleased]` notes into the new version section.
453
+
454
+ ### Changed
455
+
456
+ - Release script now creates the GitHub Release page and tag together through `gh release create`, avoiding tag-without-release failures.
457
+ - Renamed `AI_INSTRUCTIONS.md` to `AGENTS.md` and updated tool-specific instruction references.
458
+ - Updated release documentation with the single-command release workflow and GitHub CLI prerequisite.
459
+ - Improved `AGENTS.md` with non-hardcoded test guidance, explicit release prerequisites, a manual-tag prohibition, and supplemental DeepWiki/GitHub resource links.
460
+
461
+ ## [0.1.9] - 2026-08-18
462
+
463
+ ### Added
464
+
465
+ - Tests for quoted image paths, site-root paths, and exact originals-relative path resolution.
466
+ - Real-world integration coverage for preserving nested output directories and validating generated HTML paths.
467
+
468
+ ### Fixed
469
+
470
+ - **Generated post path compatibility** — image references that already include the configured originals directory, such as `assets/images/originals/subdir/photo.jpg`, are now resolved as site-root paths instead of incorrectly prepending the originals directory a second time.
471
+ - **Canonical image path documentation** — user-facing examples now use paths relative to `imgflow.originals`, such as `subdir/more_subdir/photo.jpg`, without exposing the `assets/` directory.
472
+ - **Release tooling** — version consistency checks and release-note extraction now work correctly with an `[Unreleased]` section on macOS and Linux.
473
+
474
+ ## [0.1.8] - 2026-08-17
475
+
476
+ ### Added
477
+
478
+ - **VS Code companion extension** — added the `jekyll-imgflow-vscode` companion extension. It provides image filename autocomplete for `{% imgflow %}` tags in Markdown and Liquid files, auto-discovers `imgflow.originals` from `_config.yml`, and watches the originals directory for changes.
479
+ - Tests for nested original image resolution, custom `originals` directories, and preserved output directory structure.
480
+
481
+ ### Fixed
482
+
483
+ - **Nested original image resolution** — `{% imgflow valdemar/photo.jpg %}` now correctly resolves to `assets/images/originals/valdemar/photo.jpg` instead of `assets/images/valdemar/photo.jpg`. Previously any path containing `/` was joined directly to the site source, ignoring the configured `originals` directory.
484
+ - **Output directory structure preservation** — optimized images now mirror the original directory structure under `assets/images/optimized/`. This prevents name collisions when two different folders contain images with the same basename (e.g. `valdemar/photo.jpg` vs `familie/photo.jpg`).
485
+ - **Build-time manifest path storage** — default versions are written to the source directory, but the manifest relative path was computed against `site.dest`, producing incorrect `/_site/...` entries. Now computed against `site.source` so manifest URLs are correct.
486
+ - **Parallel test race condition in temp file cleanup** — `cleanup_temp_output_files` in `spec_helper.rb` deleted ALL `imgflow-out-*` files in `Dir.tmpdir` with no age check. In parallel mode, process 0's pre-suite cleanup could delete temp files being actively used by other processes, causing sharp to fail with "No input files". Fixed by only deleting files older than 1 hour.
487
+ - **Parallel test race condition in temp file counting test** — `operation_processor_spec.rb` "cleans up temporary files" test compared global `imgflow-out-*` counts before/after processing. In parallel mode, other processes create/delete temp files between snapshots, causing false failures. Fixed by stubbing `PathResolver#temp_output_path` with a test-specific prefix so only this test's temp files are counted.
488
+
489
+ ## [0.1.7] - 2026-08-16
490
+
491
+ ### Added
492
+
493
+ - **Minimal config support** — users only need to specify `originals` and `output` in `_config.yml`. All other settings (`quality`, `formats`, `sizes`, `backend_priority`, `input_formats`) now have sensible defaults built into the `Config` class. An empty `imgflow:` block works out of the box.
494
+ - **`fallback_format` config option** — controls which format is used for the `<img>` fallback in `<picture>` elements (default: `jpg`). All other formats get `<source>` tags for browsers that support them.
495
+ - **End-to-end regression test** (`spec/realworld_build_spec.rb`) — builds a real Jekyll site with the plugin, runs `jekyll build` twice, and verifies optimized images survive in `_site/` across rebuilds. Uses 12 real-world fixture images (6 JPG, 6 GIF including 1 animated). Tagged `:slow`.
496
+ - **Format priority ordering** — `<source>` tags in `<picture>` elements are now emitted in config format priority order (avif → webp → png → jpg), so the browser picks the best format it supports.
497
+ - Documentation for image referencing limitations (no fuzzy matching/autocomplete yet).
498
+
499
+ ### Changed
500
+
501
+ - **`DEFAULT_FORMATS` reordered** from `[webp, avif, jpg, png]` to `[avif, webp, png, jpg]` — AVIF is served first (best compression), WebP as fallback for AVIF, PNG for transparency, JPG as universal `<img>` fallback.
502
+ - **`DEFAULT_BACKEND_PRIORITY` reordered** by benchmark speed: `sharp` (14s) → `libvips` (22s) → `imagemagick` (31s) → `imgproxy` (31s) → `weserv` (30s) → `flyimg`. Previous order had `imgproxy` second despite being slower.
503
+ - **Removed required-field validation** from `Config#initialize` — `originals`, `output`, `input_formats`, `formats`, and `sizes` now fall back to defaults instead of raising `ArgumentError`.
504
+ - **Fixed `HtmlGenerator` fallback logic** — previously all configured formats were treated as "fallback formats", causing all `<source>` tags to be skipped. Only the configured `fallback_format` is now skipped in the `<source>` loop.
505
+ - Updated `benchmark` gem 0.4.1 → 0.5.0 and `rubocop-performance` 1.26.1 → 1.27.0.
506
+ - Updated README.md, docs/installation.md, docs/ARCHITECTURE.md, docs/usage/tags.md with new config format, defaults table, and format priority documentation.
507
+ - Removed 113 unused test fixture images (9.6 MB → 352 KB), keeping only the 12 used by the regression test.
508
+
509
+ ### Fixed
510
+
511
+ - **Optimized images wiped from `_site` on rebuild (v0.1.6 bug)** — images were written directly to `_site/` which Jekyll clears at the start of each build. Fixed by writing to the source directory and registering generated files as `Jekyll::StaticFile` objects during the `pre_render` hook, so Jekyll copies them to `_site` during its write phase. This works on the first build (previously required two builds).
512
+ - **`keep_files: ["assets"]` removed from spec_helper.rb** — this setting masked the v0.1.6 wipe bug by preventing Jekyll from cleaning `_site/assets/` between builds. All 1064 tests pass without it.
513
+ - **Manifest path storage** — manifest now stores relative paths with leading slash (`/assets/images/optimized/...`) for consistency with Jekyll conventions.
514
+
515
+ ### Improved
516
+
517
+ - Test suite expanded from 1052 to 1064 examples with 0 failures.
518
+ - Line coverage: 97.97%.
519
+ - RuboCop: 0 offenses across all files.
520
+ - `AI_INSTRUCTIONS.md` updated with test infrastructure lessons documenting why the v0.1.6 bug went undetected.
521
+
522
+ ## [0.1.6] - 2026-08-15
523
+
524
+ ### Added
525
+
526
+ - `AnimatedGifDetector` — pure-Ruby GIF frame counter that detects animated GIFs (multiple Image Descriptor blocks) without any new gem dependencies. Supports both GIF87a and GIF89a.
527
+ - Animated GIFs are now preserved as-is during image processing: `OperationProcessor` copies the original file byte-for-byte instead of resizing or format-converting, which would destroy the animation. A warning is logged so users know the image was skipped.
528
+ - `BuildTimeProcessor` now filters out animated GIFs early in `find_original_images`, so no default versions are queued for them — avoiding unnecessary work and manifest clutter.
529
+ - Test fixtures for animated GIF (`ang-head-animation.gif`) and static single-frame GIF (`static-single-frame.gif`).
530
+ - Test coverage for the animated GIF detection and skip behavior (11 new examples).
531
+
532
+ ### Fixed
533
+
534
+ - Animated GIFs were being resized and format-converted, destroying their animation. They are now copied unchanged to the output path while still being tracked in the manifest.
535
+ - Security: updated `json` gem 2.21.1 → 2.21.2 to fix CVE-2026-71847 (crash on truncated duplicate-key streams).
536
+ - Fixed gemspec version mismatch (was still 0.1.5 after bump).
537
+ - Fixed SimpleCov deprecation warning (`add_filter` → `skip`) and removed duplicate `SimpleCov.start` call.
538
+
539
+ ### Changed
540
+
541
+ - **Minimum Ruby version bumped from 3.3.0 to 3.4.0.** Tested with Ruby 3.4.10.
542
+ - Updated `.ruby-version` to 3.4.10, `TargetRubyVersion` in `.rubocop.yml` to 3.4, CI matrix to test Ruby 3.4 only.
543
+ - Added `ostruct` and `benchmark` gems to Gemfile to silence Ruby 4.0 stdlib removal warnings.
544
+ - Updated gemspec dev dependency versions to match pinned Gemfile versions.
545
+
546
+ ### Improved
547
+
548
+ - Test suite expanded from 1005 to 1052 examples with 0 failures.
549
+ - Line coverage increased to 98.23%.
550
+ - RuboCop: fixed all 19 pre-existing offenses (global variables in `spec_helper.rb`, identical conditional branches in `imgproxy.rb`, `receive_messages` consolidation in test specs). RuboCop now passes with 0 offenses across all 102 files.
551
+ - Pinned all Gemfile dependencies to the newest verified working versions (e.g., `jekyll ~> 4.4.1`, `rubocop ~> 1.89.0`, `simplecov ~> 1.1.1`).
552
+ - Updated transitive dependencies: `csv` 3.3.5 → 3.3.6, `erb` 6.0.6 → 6.0.7, `sass-embedded` 1.101.6 → 1.102.0, `zeitwerk` 2.8.2 → 2.8.3, `rbs` 4.0.3 → 4.1.3, `dry-configurable` 1.3.0 → 1.4.0, `reline` 0.6.3 → 0.7.0, `io-console` 0.8.2 → 0.9.2.
553
+ - Remaining outdated gems (`liquid`, `rouge`, `terminal-table`, `objective_elements`, `diff-lcs`, `unicode-display_width`) are blocked by Jekyll 4.x dependency constraints and cannot be updated until Jekyll 5.x.
554
+
555
+ ## [0.1.5] - 2026-07-28
556
+
557
+ ### Added
558
+
559
+ - Unique millisecond-precision and random-suffixed temporary directories for provider and test helper output, eliminating flaky filesystem collisions.
560
+ - Explicit format-continuity inference to imgproxy, weserv, and flyimg provider URLs so chained operations preserve output formats.
561
+
562
+ ### Changed
563
+
564
+ - `provider_implementation_coverage_spec.rb` now builds `all_providers` from the full provider registry instead of `backend_priority`, so installed CLI tools (Sharp, ImageMagick, Libvips) are tested even when an HTTP provider is selected.
565
+ - Tightened provider URL generation for resize, crop, and smartcrop operations across imgproxy, weserv, and flyimg.
566
+
567
+ ### Fixed
568
+
569
+ - imgproxy resize now allows upscaling (`enlarge=1`) and preserves exact-fill dimensions.
570
+ - weserv source URL is now correctly URL-encoded and exact-fill resize is forced with `fit=fill`.
571
+ - weserv Docker test container SSRF policy and DNS resolver relaxed so `host.docker.internal` is reachable.
572
+ - flyimg crop and smartcrop parameter formats now match the Flyimg API (`e_1`, `p1x_...`, `p2x_...`, `smc_1`).
573
+ - flyimg `pns_1` default blocking upscaling is now overridden with `pns_0` for resize operations.
574
+ - flyimg shared memory allocation increased to `1gb` to avoid ImageMagick out-of-memory failures.
575
+ - Provider test suite now passes with 0 failures for default CLI, imgproxy, weserv, and flyimg configurations.
576
+
577
+ ### Improved
578
+
579
+ - Overall test reliability and code-coverage reporting (line coverage ~95-96%).
580
+
581
+ ## [0.1.1] - 2026-03-12
582
+
583
+ ### Added
584
+
585
+ - Comprehensive testing and quality assurance framework
586
+ - Automated release scripts with validation
587
+ - RuboCop code style checking
588
+ - Reek code smell detection
589
+ - Bundler audit security scanning
590
+ - RSpec test framework with coverage reporting
591
+ - Version bumping automation
592
+ - CHANGELOG template generation
593
+
594
+ ### Changed
595
+
596
+ - Improved code style with 128+ auto-corrections
597
+ - Standardized project structure and configuration
598
+ - Enhanced development workflow with quality gates
599
+
600
+ ### Fixed
601
+
602
+ - Test framework setup and module loading issues
603
+ - Version file path configuration in release scripts
604
+ - RSpec configuration and test dependencies
605
+
606
+ All notable changes to this project will be documented in this file.
607
+
608
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
609
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
data/README.md CHANGED
@@ -15,6 +15,19 @@ A [Jekyll](https://jekyllrb.com/) plugin for automatic image optimization with m
15
15
  [![VS Code Extension](https://img.shields.io/badge/VS%20Code%20Companion-jekyll--imgflow-blue?logo=visual-studio-code)](https://github.com/gundestrup/jekyll-imgflow-vscode)
16
16
  [![License](https://img.shields.io/github/license/gundestrup/jekyll-imgflow)](LICENSE)
17
17
 
18
+ <!-- markdownlint-disable MD033 -->
19
+ <picture>
20
+ <source
21
+ srcset="docs/assets/jekyll-imgflow-demo.avif"
22
+ type="image/avif">
23
+ <source
24
+ srcset="docs/assets/jekyll-imgflow-demo.webp"
25
+ type="image/webp">
26
+ <img src="docs/assets/jekyll-imgflow-demo.png"
27
+ alt="jekyll-imgflow demo">
28
+ </picture>
29
+ <!-- markdownlint-enable MD033 -->
30
+
18
31
  ## 🚀 Quick Start
19
32
 
20
33
  ```bash
@@ -45,6 +58,19 @@ imgflow:
45
58
  > For editor autocomplete while writing `{% imgflow %}` tags, install the
46
59
  > [VS Code companion extension](https://github.com/gundestrup/jekyll-imgflow-vscode).
47
60
 
61
+ <!-- markdownlint-disable MD033 -->
62
+ <picture>
63
+ <source
64
+ srcset="https://raw.githubusercontent.com/gundestrup/jekyll-imgflow-vscode/main/docs/assets/image-flow.avif"
65
+ type="image/avif">
66
+ <source
67
+ srcset="https://raw.githubusercontent.com/gundestrup/jekyll-imgflow-vscode/main/docs/assets/image-flow.webp"
68
+ type="image/webp">
69
+ <img src="https://raw.githubusercontent.com/gundestrup/jekyll-imgflow-vscode/main/docs/assets/image-flow.png"
70
+ alt="jekyll-imgflow-vscode: filename, width/format and markup parameter autocomplete">
71
+ </picture>
72
+ <!-- markdownlint-enable MD033 -->
73
+
48
74
  ## ✨ Key Features
49
75
 
50
76
  - **Multiple Providers**: [Sharp](https://github.com/lovell/sharp), [ImageMagick](https://github.com/ImageMagick/ImageMagick), [LibVips](https://github.com/libvips/libvips), [Imgproxy](https://github.com/imgproxy/imgproxy), [Weserv](https://github.com/weserv/images), [Flyimg](https://github.com/flyimg/flyimg)
data/interface.yml CHANGED
@@ -2,7 +2,7 @@
2
2
  # Public tag/config surface for tooling (editor extensions, doc linters).
3
3
  ---
4
4
  gem: jekyll-imgflow
5
- version: 0.4.4
5
+ version: 0.4.5
6
6
  tags:
7
7
  imgflow:
8
8
  params:
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JekyllImgFlow
4
- VERSION = "0.4.4"
4
+ VERSION = "0.4.5"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-imgflow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Svend Gundestrup
@@ -44,6 +44,9 @@ dependencies:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
46
  version: '4.0'
47
+ - - "<"
48
+ - !ruby/object:Gem::Version
49
+ version: '5.0'
47
50
  type: :runtime
48
51
  prerelease: false
49
52
  version_requirements: !ruby/object:Gem::Requirement
@@ -51,15 +54,28 @@ dependencies:
51
54
  - - ">="
52
55
  - !ruby/object:Gem::Version
53
56
  version: '4.0'
54
- description: ImgFlow provides automatic image optimization for Jekyll with support
55
- for multiple providers (Sharp, ImageMagick, LibVips, Imgproxy, Weserv, Flyimg),
56
- multiple formats (AVIF, WebP, PNG, JPG), and responsive image generation with modern
57
- picture tags.
57
+ - - "<"
58
+ - !ruby/object:Gem::Version
59
+ version: '5.0'
60
+ description: |
61
+ == Jekyll image optimization
62
+
63
+ ImgFlow provides automatic image optimization for Jekyll with multiple
64
+ providers (Sharp, ImageMagick, LibVips, Imgproxy, Weserv, Flyimg) and
65
+ formats (AVIF, WebP, PNG, JPG).
66
+
67
+ * Responsive picture-tag output with automatic format fallbacks
68
+ * Build-time pre-generation and on-demand specialized versions
69
+ * Presets, crop, watermark and size parameters
70
+
71
+ A companion VS Code extension (jekyll-imgflow-vscode) provides tag
72
+ autocomplete: https://github.com/gundestrup/jekyll-imgflow-vscode
58
73
  email: svend@gundestrup.dk
59
74
  executables: []
60
75
  extensions: []
61
76
  extra_rdoc_files: []
62
77
  files:
78
+ - CHANGELOG.md
63
79
  - LICENSE
64
80
  - README.md
65
81
  - interface.yml
@@ -113,6 +129,10 @@ licenses:
113
129
  - AGPL-3.0-or-later
114
130
  metadata:
115
131
  rubygems_mfa_required: 'true'
132
+ homepage_uri: https://github.com/gundestrup/jekyll-imgflow
133
+ source_code_uri: https://github.com/gundestrup/jekyll-imgflow
134
+ changelog_uri: https://github.com/gundestrup/jekyll-imgflow/blob/main/CHANGELOG.md
135
+ bug_tracker_uri: https://github.com/gundestrup/jekyll-imgflow/issues
116
136
  icon_uri: https://raw.githubusercontent.com/gundestrup/jekyll-imgflow/v0.1.11/docs/assets/images/jekyll-imgflow-icon.png
117
137
  rdoc_options: []
118
138
  require_paths: