Skip to content

feat: add image path autocomplete option#92

Merged
lorenzopantano merged 3 commits intomainfrom
feat/issue-89-autocomplete-image-path
Apr 3, 2026
Merged

feat: add image path autocomplete option#92
lorenzopantano merged 3 commits intomainfrom
feat/issue-89-autocomplete-image-path

Conversation

@lorenzopantano
Copy link
Copy Markdown
Contributor

Closes #89

Changes

  • Add autocomplete_paths option to ImagesConfig to enable automatic expansion of TMDB image paths to full URLs
  • Create ImageAPI.autocompleteImagePaths() method for recursive response transformation
  • Wire path autocompletion into ApiClient response pipeline (applied before user interceptors)
  • Forward images config from TMDB class to shared client
  • Add comprehensive test coverage for new transformer logic and type guards
  • Improve ImageAPI test coverage to 100% (statements, branches)

Features

  • Opt-in behavior: disabled by default to preserve existing semantics
  • Respects configured default_image_sizes for each image type
  • Handles nested objects and arrays, file_path fields in image collections
  • Preserves absolute URLs and non-image string values
  • Works transparently with existing user response interceptors

Example

const tmdb = new TMDB(token, {
  images: {
    autocomplete_paths: true,
    default_image_sizes: { posters: "original" }
  }
});

const movie = await tmdb.movies.details({ movie_id: 550 });
console.log(movie.poster_path); 
// "https://image.tmdb.org/t/p/original/poster.jpg"

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lorenzopant-tmdb-docs Ready Ready Preview, Comment Apr 3, 2026 8:29pm

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Add automatic TMDB image path expansion with opt-in autocomplete option

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add autocomplete_paths option to enable automatic TMDB image path expansion
• Implement recursive response transformation in ImageAPI.autocompleteImagePaths()
• Integrate path autocompletion into ApiClient response pipeline before user interceptors
• Forward images config from TMDB class through to ApiClient
• Refactor type guards into dedicated utils/types.ts module
• Add comprehensive test coverage for path autocompletion logic
Diagram
flowchart LR
  A["TMDB Config<br/>images.autocomplete_paths"] -->|"passes to"| B["ApiClient"]
  B -->|"creates"| C["ImageAPI<br/>if enabled"]
  D["API Response"] -->|"flows through"| E["sanitizeNulls"]
  E -->|"transforms via"| C
  C -->|"autocompleteImagePaths"| F["Expanded URLs"]
  F -->|"passes to"| G["User Interceptor"]
  G -->|"returns"| H["Final Response"]
Loading

Grey Divider

File Changes

1. packages/tmdb/src/client.ts ✨ Enhancement +9/-3

Wire image autocompletion into response pipeline

packages/tmdb/src/client.ts


2. packages/tmdb/src/images/images.ts ✨ Enhancement +86/-1

Implement recursive image path autocompletion logic

packages/tmdb/src/images/images.ts


3. packages/tmdb/src/tmdb.ts ✨ Enhancement +1/-0

Forward images config to ApiClient constructor

packages/tmdb/src/tmdb.ts


View more (6)
4. packages/tmdb/src/types/config/images.ts ✨ Enhancement +8/-0

Add autocomplete_paths boolean option to ImagesConfig

packages/tmdb/src/types/config/images.ts


5. packages/tmdb/src/utils/index.ts Refactoring +1/-49

Reorganize type guards into dedicated types module

packages/tmdb/src/utils/index.ts


6. packages/tmdb/src/utils/types.ts ✨ Enhancement +59/-0

Create new module with isRecord and image path guards

packages/tmdb/src/utils/types.ts


7. packages/tmdb/src/tests/images/images.test.ts 🧪 Tests +74/-0

Add comprehensive tests for autocompleteImagePaths method

packages/tmdb/src/tests/images/images.test.ts


8. packages/tmdb/src/tests/utils/index.test.ts 🧪 Tests +0/-107

Remove type guard tests moved to types.test.ts

packages/tmdb/src/tests/utils/index.test.ts


9. packages/tmdb/src/tests/utils/types.test.ts 🧪 Tests +66/-0

Add tests for isRecord and image path type guards

packages/tmdb/src/tests/utils/types.test.ts


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Apr 3, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (1) 🎨 UX Issues (0)

Grey Divider


Action required

1. autocomplete_paths gates URL expansion 📎 Requirement gap ≡ Correctness
Description
Image path autocompletion is only enabled when options.images?.autocomplete_paths is explicitly
set, so TMDB image path fields can still be returned as raw partial paths even when default image
options exist. This violates the requirement to autocomplete image path fields to full URLs using
default options rather than requiring an opt-in flag.
Code

packages/tmdb/src/client.ts[49]

+		this.imageApi = options.images?.autocomplete_paths ? new ImageAPI(options.images) : undefined;
Evidence
PR Compliance ID 1 requires API responses with TMDB image path fields (e.g., poster_path) to be
expanded into full URLs using default options. The client only instantiates and applies the
transformer when autocomplete_paths is true, and the config docs state this behavior is disabled
by default—so by default responses will continue returning raw paths.

Autocomplete TMDB image paths (poster_path and other image fields) to full URLs using default options
packages/tmdb/src/client.ts[49-49]
packages/tmdb/src/client.ts[265-265]
packages/tmdb/src/types/config/images.ts[65-72]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The API response transformation only autocompletes TMDB image path fields when `images.autocomplete_paths` is explicitly enabled, which contradicts the requirement to expand image paths using default options.
## Issue Context
The response pipeline already supports transforming sanitized responses via `ImageAPI.autocompleteImagePaths()`, but transformer construction is gated behind `autocomplete_paths`, and the config docs explicitly describe it as disabled by default.
## Fix Focus Areas
- packages/tmdb/src/client.ts[49-49]
- packages/tmdb/src/client.ts[265-272]
- packages/tmdb/src/types/config/images.ts[65-72]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Prototype-key crash path🐞 Bug ⛨ Security
Description
ImageAPI uses the in operator to decide whether a response key is a supported image
field/collection; this can return true for prototype keys (e.g., toString, __proto__) and then
buildImageUrl() will attempt to call a non-image method via this[method](...), throwing at
runtime. Because this runs on untrusted res.json() data when autocomplete_paths is enabled, a
single unexpected key can break all responses.
Code

packages/tmdb/src/images/images.ts[R94-116]

+	private isImageCollectionKey(value: string): value is ImageCollectionKey {
+		return value in IMAGE_COLLECTION_BUILDERS;
+	}
+
+	private isFullUrl(path: string): boolean {
+		return /^https?:\/\//.test(path);
+	}
+
+	private buildImageUrl(key: ImagePathKey, path: string): string {
+		const method = IMAGE_PATH_BUILDERS[key];
+		return this[method](path);
+	}
+
+	private transformPathValue(key: string, value: string, collectionKey?: ImageCollectionKey): string {
+		if (!value.startsWith("/") || this.isFullUrl(value)) return value;
+
+		if (key in IMAGE_PATH_BUILDERS) {
+			return this.buildImageUrl(key as ImagePathKey, value);
+		}
+
+		if (key === "file_path" && collectionKey) {
+			return this.buildImageUrl(IMAGE_COLLECTION_BUILDERS[collectionKey], value);
+		}
Evidence
isImageCollectionKey() and transformPathValue() use value in IMAGE_COLLECTION_BUILDERS / `key
in IMAGE_PATH_BUILDERS`, which consults the prototype chain; if a response object includes an own
property named like a prototype key (e.g., toString with a value starting with /), it will be
treated as supported and routed into buildImageUrl(), where IMAGE_PATH_BUILDERS[key] can resolve
to an inherited property and this[method](...) can throw. The ApiClient feeds res.json() output
into this transformer when enabled.

packages/tmdb/src/images/images.ts[70-119]
packages/tmdb/src/client.ts[263-270]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ImageAPI.autocompleteImagePaths()` uses the `in` operator to test membership in `IMAGE_PATH_BUILDERS` / `IMAGE_COLLECTION_BUILDERS`. `in` checks the prototype chain, so keys like `toString`, `constructor`, or `__proto__` can be misidentified as valid builders, leading to invalid dynamic dispatch (`this[method](...)`) and runtime exceptions during response transformation.
### Issue Context
This code runs on untrusted `res.json()` response data when `images.autocomplete_paths` is enabled, so it must not be sensitive to prototype keys.
### Fix Focus Areas
- packages/tmdb/src/images/images.ts[94-116]
- packages/tmdb/src/images/images.ts[102-105]
- packages/tmdb/src/images/images.ts[79-90]
### Suggested fix
- Replace `value in IMAGE_COLLECTION_BUILDERS` with an own-property check (e.g., `Object.hasOwn(IMAGE_COLLECTION_BUILDERS, value)` or `Object.prototype.hasOwnProperty.call(...)`).
- Replace `key in IMAGE_PATH_BUILDERS` with an own-property check.
- Consider creating `transformed` via `Object.create(null)` (or explicitly guarding `__proto__`/`constructor` keys) to avoid prototype setter behavior when copying arbitrary keys from responses.
- Optionally harden `buildImageUrl()` by ensuring `method` is a string key of `this` before calling.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Non-plain objects flattened🐞 Bug ☼ Reliability
Description
autocompleteImagePaths() treats any non-array object as a record and rebuilds it as a plain {}
using Object.entries, which drops prototypes and non-enumerable properties (e.g., Date becomes
{}). Since isRecord() explicitly returns true for object instances, callers using
autocompleteImagePaths() on non-JSON objects can experience silent data/type loss.
Code

packages/tmdb/src/images/images.ts[R70-91]

+	public autocompleteImagePaths<T>(value: T, collectionKey?: ImageCollectionKey): T {
+		if (Array.isArray(value)) {
+			return value.map((entry) => this.autocompleteImagePaths(entry, collectionKey)) as T;
+		}
+
+		if (!isRecord(value)) {
+			return value;
+		}
+
+		const transformed: Record<string, unknown> = {};
+		for (const [key, entry] of Object.entries(value)) {
+			if (typeof entry === "string") {
+				transformed[key] = this.transformPathValue(key, entry, collectionKey);
+				continue;
+			}
+
+			const nextCollectionKey = this.isImageCollectionKey(key) ? key : collectionKey;
+			transformed[key] = this.autocompleteImagePaths(entry, nextCollectionKey);
+		}
+
+		return transformed as T;
+	}
Evidence
isRecord() is defined as “any non-null object that is not an array” and tests explicitly assert
isRecord(new Date()) === true. autocompleteImagePaths() then rebuilds any such object into a new
plain object by iterating enumerable entries, which for many instances (like Date) is empty,
producing {} and losing the original instance type/prototype.

packages/tmdb/src/images/images.ts[70-91]
packages/tmdb/src/utils/types.ts[3-10]
packages/tmdb/src/tests/utils/types.test.ts[5-13]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ImageAPI.autocompleteImagePaths()` rebuilds any `isRecord()` object into a new plain object, which can corrupt non-plain objects (Date/class instances) by stripping prototypes and non-enumerable properties.
### Issue Context
While `ApiClient` feeds JSON responses (plain objects) into this transformer, `autocompleteImagePaths()` is a public method and can be called directly by users with arbitrary objects.
### Fix Focus Areas
- packages/tmdb/src/images/images.ts[70-91]
- packages/tmdb/src/utils/types.ts[3-10]
### Suggested fix
- Use a stricter predicate inside `autocompleteImagePaths()` (e.g., `isPlainObject`) instead of `isRecord`, such as:
- `Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null`
- Alternatively, if you want to support class instances, preserve the prototype when cloning (e.g., `const transformed = Object.create(Object.getPrototypeOf(value))`) and copy properties safely.
- Add a small unit test demonstrating the intended behavior for `Date`/class instances (either preserved or explicitly not transformed).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@lorenzopantano lorenzopantano self-assigned this Apr 3, 2026
@lorenzopantano lorenzopantano added the enhancement New feature or request label Apr 3, 2026
this.requestInterceptors = raw == null ? [] : Array.isArray(raw) ? raw : [raw];
this.onSuccessInterceptor = options.interceptors?.response?.onSuccess;
this.onErrorInterceptor = options.interceptors?.response?.onError;
this.imageApi = options.images?.autocomplete_paths ? new ImageAPI(options.images) : undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. autocomplete_paths gates url expansion 📎 Requirement gap ≡ Correctness

Image path autocompletion is only enabled when options.images?.autocomplete_paths is explicitly
set, so TMDB image path fields can still be returned as raw partial paths even when default image
options exist. This violates the requirement to autocomplete image path fields to full URLs using
default options rather than requiring an opt-in flag.
Agent Prompt
## Issue description
The API response transformation only autocompletes TMDB image path fields when `images.autocomplete_paths` is explicitly enabled, which contradicts the requirement to expand image paths using default options.

## Issue Context
The response pipeline already supports transforming sanitized responses via `ImageAPI.autocompleteImagePaths()`, but transformer construction is gated behind `autocomplete_paths`, and the config docs explicitly describe it as disabled by default.

## Fix Focus Areas
- packages/tmdb/src/client.ts[49-49]
- packages/tmdb/src/client.ts[265-272]
- packages/tmdb/src/types/config/images.ts[65-72]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@lorenzopantano lorenzopantano merged commit 8601d96 into main Apr 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Image Autocomplete

1 participant