Skip to content

feat(directus): add Sharp transforms & key modifier.#2207

Open
kheiner wants to merge 7 commits into
nuxt:mainfrom
kheiner:feat/add-directus-transform-types
Open

feat(directus): add Sharp transforms & key modifier.#2207
kheiner wants to merge 7 commits into
nuxt:mainfrom
kheiner:feat/add-directus-transform-types

Conversation

@kheiner
Copy link
Copy Markdown
Contributor

@kheiner kheiner commented Apr 9, 2026

🔗 Linked issue

fixes #2194

📚 Description

  • (feature): Support for Keyed Transforms using the key string, stripping all other transforms supported by Nuxt/Image
    • (test): Ensure that key if present is not paired with other modifiers.
    • (playground): Identify Directus instance that has pre-configured keys in the public space for better explanation to developers.
  • (feature): Transforms should have typing for Image Operations, Color Manipulation, and Channel Manipulation as supported by Sharp.
  • (fix): The current transforms are typed as string[] which is not valid. Transforms should fallback to a tuple of type [string, ...any[]][] to prevent errors with using transforms not typed explicitly. (Future proofing for new transforms added to Sharp & supported by Directus.)
  • (docs): Update Docs ->
    • Explain key modifier.
    • Explicitly name Sharp Transforms that are supported (and link to details in Sharp Library)

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 9, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@nuxt/image@2207

commit: fb2c1ff

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 9, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 32.52%. Comparing base (671e5d0) to head (fb2c1ff).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2207   +/-   ##
=======================================
  Coverage   32.52%   32.52%           
=======================================
  Files           7        7           
  Lines         372      372           
  Branches      131      131           
=======================================
  Hits          121      121           
  Misses        194      194           
  Partials       57       57           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why the tests specifically care about the order, nor did I do extensive research on why I needed to put the requests in a different order than the sources for a successful test. If I'm hiding a problem here, I'd like to know about it but as far as I can tell the order has no meaning outside of the test.

Comment thread src/runtime/providers/directus.ts Outdated
Copy link
Copy Markdown
Contributor Author

@kheiner kheiner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking forward to the feedback.

@kheiner kheiner marked this pull request as ready for review April 9, 2026 11:57
@kheiner kheiner requested a review from danielroe as a code owner April 9, 2026 11:57
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 9, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This pull request implements typed Sharp operation support and keyed transform functionality for the Directus image provider. The core provider implementation adds type-safe Sharp operation definitions, supports mutually-exclusive keyed transforms via modifiers.key, introduces optional top-level image parameters (width, height, quality, format, fit), and refactors URL generation logic. Documentation is expanded with Directus-specific modifier guidance and tabbed examples. The playground configuration and test fixtures are updated to reference a hosted sandbox instance, and new test cases validate both standard and keyed transform behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature additions: Sharp transforms support and the new key modifier for Directus.
Description check ✅ Passed The description clearly relates to the changeset by referencing the linked issue #2194 and outlining the completed feature objectives.
Linked Issues check ✅ Passed All coding requirements from issue #2194 are met: keyed transforms with key support [directus.ts, directus.md, playground], Sharp operation typing [directus.ts], transforms tuple typing [directus.ts], documentation updates [directus.md], and tests validating key behavior [providers.test.ts, directus.json5].
Out of Scope Changes check ✅ Passed All changes directly support the PR objectives: documentation, type definitions, implementation, configuration updates, test coverage, and playground examples for Directus keyed transforms and Sharp typing.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/runtime/providers/directus.ts (1)

102-114: Transforms deduplication approach works but has a minor inefficiency.

The JSON stringify/parse approach for deduplication is functional but performs redundant parsing. Consider using a Map or filtering duplicates in a single pass for better performance, though this is a minor concern given typical transform array sizes.

♻️ Alternative deduplication approach
 const operationsGenerator = createOperationsGenerator({
   valueMap: {
     transforms(value: SharpOperation[]) {
-      return value.length > 0
-        ? JSON.stringify(
-            Array.from(new Set(value.map(v => JSON.stringify(v))))
-              .map(v => JSON.parse(v)),
-          )
-        : undefined
+      if (value.length === 0) return undefined
+      const seen = new Set<string>()
+      const unique = value.filter((v) => {
+        const key = JSON.stringify(v)
+        if (seen.has(key)) return false
+        seen.add(key)
+        return true
+      })
+      return JSON.stringify(unique)
     },
   },
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/providers/directus.ts` around lines 102 - 114, The transforms
valueMap currently deduplicates by JSON.stringify/parse which works but does
extra parsing; update the transforms function inside createOperationsGenerator
(the operationsGenerator/valueMap/transforms handler for SharpOperation[]) to
deduplicate in a single pass (e.g., use a Map or Set of serialized entries to
filter duplicates while building the resulting array) and then JSON.stringify
that deduplicated array (return undefined for empty), keeping the same return
shape and types as before.
docs/content/3.providers/directus.md (1)

41-41: Minor: Use hyphen for compound adjective.

For grammatical correctness, "Directus specific" should be "Directus-specific" when used as a compound adjective.

📝 Proposed fix
-The `modifiers` object is used for Directus specific features. All modifiers are optional.
+The `modifiers` object is used for Directus-specific features. All modifiers are optional.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/content/3.providers/directus.md` at line 41, Update the sentence
describing the "modifiers" object to use a hyphenated compound adjective: change
"Directus specific features" to "Directus-specific features" so the phrase
correctly reads "The `modifiers` object is used for Directus-specific features.
All modifiers are optional." Ensure the `modifiers` symbol remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@docs/content/3.providers/directus.md`:
- Line 41: Update the sentence describing the "modifiers" object to use a
hyphenated compound adjective: change "Directus specific features" to
"Directus-specific features" so the phrase correctly reads "The `modifiers`
object is used for Directus-specific features. All modifiers are optional."
Ensure the `modifiers` symbol remains unchanged.

In `@src/runtime/providers/directus.ts`:
- Around line 102-114: The transforms valueMap currently deduplicates by
JSON.stringify/parse which works but does extra parsing; update the transforms
function inside createOperationsGenerator (the
operationsGenerator/valueMap/transforms handler for SharpOperation[]) to
deduplicate in a single pass (e.g., use a Map or Set of serialized entries to
filter duplicates while building the resulting array) and then JSON.stringify
that deduplicated array (return undefined for empty), keeping the same return
shape and types as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6c8abb98-16cf-45a3-8906-78b5a8da1ec5

📥 Commits

Reviewing files that changed from the base of the PR and between e3ce805 and 7693343.

📒 Files selected for processing (7)
  • docs/content/3.providers/directus.md
  • playground/app/providers.ts
  • playground/nuxt.config.ts
  • src/runtime/providers/directus.ts
  • test/e2e/__snapshots__/directus.json5
  • test/nuxt/providers.test.ts
  • test/providers.ts

@kheiner kheiner changed the title feat: add directus transform types feat(directus): add Sharp transforms & key modifier. Apr 11, 2026
@kheiner
Copy link
Copy Markdown
Contributor Author

kheiner commented Apr 20, 2026

Really hoping that I can get this added in to v2.1.0 #2028

let me know if there's anything needed on my end.

kheiner and others added 7 commits May 13, 2026 09:54
Intentionally omitting Resizing operations at the moment due to coverage in Nuxt/Image and abstraction available to Directus.

TODO: Fix duplication of transform object.
Updated Directus playground/e2e_snapshots to use the Directus Sandbox.
…orms

Fixes nuxt#2194

* Implements the ability to use a `key` to use a preconfigured Directus
Transform set.
* Adds Types for Sharp Transforms [intentionally omitted resizing since
the basic functionality is abstracted in the nuxt/image module]
* Fixes issue of incorrect typing for transforms to allow for `[string,
...any[]]` (was incorrectly typed as `string[]`)
Whitespace was causing tests to fail;
* Sort import for `providers.test.ts` (NOTE: PR nuxt#2193 greatly improves
test and readability)
* Add E2E snapshot for `key` modifier.
* Fix missing test in `providers.test.ts`
* Add `key` test for `providers.test.ts`
Updated Docs to include:
* `key` :modifier
* Explain Sharp Transforms and provide examples.
Remove unnecessary comments
@kheiner kheiner force-pushed the feat/add-directus-transform-types branch from ef4a3f1 to fb2c1ff Compare May 13, 2026 16:54
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
docs/content/3.providers/directus.md (1)

119-120: ⚡ Quick win

Document that key is mutually exclusive with other modifiers.

The key field description should explicitly state it cannot be combined with other image modifiers, since that’s a core behavior of this feature.

Suggested doc wording
-::field{name="key" type="string"}
-Sets a unique identifier for allowing faster and easier image transformation requests.
+::field{name="key" type="string"}
+Sets a unique identifier for a pre-configured Directus transform. When `key` is provided, do not combine it with other modifiers.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/3.providers/directus.md` around lines 119 - 120, Update the
::field{name="key" type="string"} description to explicitly state that the key
is mutually exclusive with other image modifiers: mention that when a key is
provided all other image transformation/modifier query parameters or settings
are ignored and cannot be combined with the key, and provide a short suggested
sentence such as "This unique key cannot be used together with any other image
modifiers; when a key is present, other transformation parameters are ignored."
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/content/3.providers/directus.md`:
- Around line 51-53: The example object uses a string for the withoutEnlargement
property (currently 'true') while the field is documented as a boolean; update
the example in the :modifiers object to use the boolean true (without quotes)
for withoutEnlargement so it matches the documented type and prevents copy-paste
errors when using the withoutEnlargement option.
- Line 82: The docs use an invalid TypeScript tuple-array for the "transforms"
field: change the type in the ::field{name="transforms"} declaration from
"['string', ...any][]" to the correct tuple-array syntax "[string, ...any[]][]"
so the first element is a string type and the rest are any[]; update the
declaration for the transforms field to use [string, ...any[]][] accordingly.

---

Nitpick comments:
In `@docs/content/3.providers/directus.md`:
- Around line 119-120: Update the ::field{name="key" type="string"} description
to explicitly state that the key is mutually exclusive with other image
modifiers: mention that when a key is provided all other image
transformation/modifier query parameters or settings are ignored and cannot be
combined with the key, and provide a short suggested sentence such as "This
unique key cannot be used together with any other image modifiers; when a key is
present, other transformation parameters are ignored."
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 83639579-91c9-49de-b1c1-330932c0b9d2

📥 Commits

Reviewing files that changed from the base of the PR and between 7693343 and fb2c1ff.

📒 Files selected for processing (7)
  • docs/content/3.providers/directus.md
  • playground/app/providers.ts
  • playground/nuxt.config.ts
  • src/runtime/providers/directus.ts
  • test/e2e/__snapshots__/directus.json5
  • test/nuxt/providers.test.ts
  • test/providers.ts
✅ Files skipped from review due to trivial changes (1)
  • test/e2e/snapshots/directus.json5
🚧 Files skipped from review as they are similar to previous changes (5)
  • playground/nuxt.config.ts
  • test/nuxt/providers.test.ts
  • test/providers.ts
  • playground/app/providers.ts
  • src/runtime/providers/directus.ts

Comment on lines 51 to 53
:modifiers="{
height: '512',
withoutEnlargement: 'true',
transforms: [['blur', 4], ['negate']]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use boolean in the withoutEnlargement example, not string.

Line 52 uses 'true' (string), but Line 78 documents this field as boolean. This copy-paste example should use true to prevent incorrect usage.

Suggested doc fix
-    withoutEnlargement: 'true',
+    withoutEnlargement: true,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
:modifiers="{
height: '512',
withoutEnlargement: 'true',
transforms: [['blur', 4], ['negate']]
:modifiers="{
withoutEnlargement: true,
transforms: [['blur', 4], ['negate']]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/3.providers/directus.md` around lines 51 - 53, The example
object uses a string for the withoutEnlargement property (currently 'true')
while the field is documented as a boolean; update the example in the :modifiers
object to use the boolean true (without quotes) for withoutEnlargement so it
matches the documented type and prevents copy-paste errors when using the
withoutEnlargement option.

Disable automatically upscaling the image when true.
::

::field{name="transforms" type="['string', ...any][]"}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# Read the file around line 82 to see the actual content
cat -n docs/content/3.providers/directus.md | sed -n '75,90p'

Repository: nuxt/image

Length of output: 940


🏁 Script executed:

# Also check if there's any TypeScript definition or PR description that clarifies the intended type
fd -t f -e ts -e d.ts | head -20 | xargs grep -l "transforms" 2>/dev/null | head -5

Repository: nuxt/image

Length of output: 82


🏁 Script executed:

# Search for any references to the transforms type in the codebase
rg "transforms.*type" --type markdown -A 2 -B 2

Repository: nuxt/image

Length of output: 395


🏁 Script executed:

# Search for the transforms type definition in TypeScript source files
rg "transforms\s*:" --type ts -A 3 -B 1 | head -50

Repository: nuxt/image

Length of output: 329


🏁 Script executed:

# Look for Directus provider implementation to understand the actual type
fd -t f -name "*directus*" | grep -E "\.(ts|js)$"

Repository: nuxt/image

Length of output: 285


🏁 Script executed:

# Check if there's any type definition file that shows the transforms type
rg "transforms.*\[.*\]" --type ts -A 1 | head -30

Repository: nuxt/image

Length of output: 465


🏁 Script executed:

# Find where SharpOperation is defined
rg "type SharpOperation|interface SharpOperation" --type ts -A 5

Repository: nuxt/image

Length of output: 888


🏁 Script executed:

# Also check the imports and type definitions in the directus provider
cat -n src/runtime/providers/directus.ts | head -40

Repository: nuxt/image

Length of output: 2043


🏁 Script executed:

# Get more of the directus.ts file to see the full SharpOperation type definition
cat -n src/runtime/providers/directus.ts | sed -n '40,120p'

Repository: nuxt/image

Length of output: 2784


🏁 Script executed:

# Also check if there are any type definitions that match the tuple with rest pattern
rg "\[string.*\]" --type ts -A 1 -B 1 | head -20

Repository: nuxt/image

Length of output: 642


🏁 Script executed:

# Let me verify the TypeScript rest element syntax is correct
# Check for similar patterns in the codebase
rg "\.\.\." --type ts -B 1 -A 1 | grep -E "^\s*\[.*\.\.\." | head -10

Repository: nuxt/image

Length of output: 36


🏁 Script executed:

# Look at the actual usage in the playground to understand what the transforms value looks like
cat -n playground/app/providers.ts | grep -A 3 -B 3 "transforms"

Repository: nuxt/image

Length of output: 549


Fix transforms type notation to valid TypeScript tuple-array syntax.

Line 82 currently shows ['string', ...any][], which uses invalid TypeScript syntax. The quoted string literal 'string' should be the unquoted string type, and the rest element must be written as ...any[]. Use [string, ...any[]][] to accurately represent the tuple structure where each transform is an array starting with an operation name (string) followed by any arguments.

Suggested doc fix
-::field{name="transforms" type="['string', ...any][]"}
+::field{name="transforms" type="[string, ...any[]][]"}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
::field{name="transforms" type="['string', ...any][]"}
::field{name="transforms" type="[string, ...any[]][]"}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/3.providers/directus.md` at line 82, The docs use an invalid
TypeScript tuple-array for the "transforms" field: change the type in the
::field{name="transforms"} declaration from "['string', ...any][]" to the
correct tuple-array syntax "[string, ...any[]][]" so the first element is a
string type and the rest are any[]; update the declaration for the transforms
field to use [string, ...any[]][] accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] (provider/directus) Add Sharp transforms to modifiers, add support for keyed transforms

2 participants