Repository navigation
feat: add Format constants for convert media types, including JXL - #55
Conversation
|
👍 imo we can create a release (bump version and changelog) |
|
Also update the |
There was a problem hiding this comment.
🟡 Changes recommended
The PR description’s claimed negative type assertions are not present in the typing test, and there’s a small correctness issue in the new Format documentation (JPG described as an alias despite differing value).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds a runtime-discoverable tinify.Format constants object so consumers can reference supported convert media types at runtime (not only via TypeScript literal unions), aligning this client with the other Tinify libraries.
Changes:
- Introduces
src/tinify/Format.tsand wires it onto the publictinifyexport astinify.Format. - Refactors
SupportedImageTypes/WildcardOrSupportedImageTypesto be derived fromFormat(avoiding drift). - Updates typing tests and docs/changelog to include the new constants and formats (e.g., JXL, AVIF).
File summaries
| File | Description |
|---|---|
| test/tinify-typing-test.ts | Extends TS typing coverage for convert to include new formats and tinify.Format constants. |
| src/tinify/Source.ts | Derives SupportedImageTypes and wildcard type from Format rather than duplicating literals. |
| src/tinify/Format.ts | Adds the runtime Format constants object for supported convert media types. |
| src/tinify.ts | Adds Format onto the Tinify instance type so it’s available in generated typings. |
| src/index.ts | Attaches Format to the exported tinify object at runtime (tinify.Format = Format). |
| README.md | Updates format lists to include JXL in the documented capabilities. |
| CHANGES.md | Documents the new tinify.Format API under Unreleased. |
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| await tinify.fromFile("/foo/bar").convert({ type: "*/*" }) | ||
|
|
||
| // The Format constants are accepted everywhere a literal is. | ||
| await tinify.fromFile("/foo/bar").convert({ type: tinify.Format.JXL }) | ||
| await tinify.fromFile("/foo/bar").convert({ type: tinify.Format.ANY }) | ||
| await tinify.fromFile("/foo/bar").convert({ | ||
| type: [tinify.Format.JXL, tinify.Format.WEBP], | ||
| }) | ||
|
|
There was a problem hiding this comment.
Fixed in 080cf91 — the two assertions are now in this file:
// @ts-expect-error an unknown media type is not assignable
await tinify.fromFile("/foo/bar").convert({ type: "image/bogus" })
// @ts-expect-error the "*/*" wildcard is not valid inside the array form
await tinify.fromFile("/foo/bar").convert({ type: ["*/*"] })They are self-enforcing: an @ts-expect-error that does not fire is itself a compile error, so if the derived union ever widens, npm test fails on the directive rather than silently passing.
| /** JPEG, an alias of `JPEG`. */ | ||
| JPG: "image/jpg", |
There was a problem hiding this comment.
Fixed in 080cf91. Reworded to "JPEG, under the alternative media type the API also accepts. This is a distinct value from JPEG, not an alias for it."
Both are separate members of the API's mediaType enum, so they are two accepted spellings rather than equal constants. Applied the same wording to the other five client libraries for consistency.
| type FormatValues = (typeof Format)[keyof typeof Format]; | ||
|
|
||
| export type SupportedImageTypes = Exclude<FormatValues, typeof Format.ANY>; |
There was a problem hiding this comment.
Not changing this one — the premise looks wrong. This file already uses semicolons on exactly these declarations, on master, before this PR:
export type SupportedImageTypes = "image/webp"
| "image/png"
| "image/jpg"; // line 13
export type WildcardOrSupportedImageTypes = SupportedImageTypes
| "*/*"; // line 16
export type ConvertOptions = {
type: WildcardOrSupportedImageTypes | SupportedImageTypes[]; // line 19
}The convention here is semicolon-free statements (imports, expressions) but semicolons terminating type alias and member declarations. The new aliases follow that, so removing them would be the inconsistent change. Happy to go either way if the maintainers prefer a different rule, but this matches what is already there.
|
Addressed both of your comments in 080cf91: Release — bumped to README — added a worked example next to the existing convert snippet: // Convert format using the Format constants
// (tinify.Format.WEBP, PNG, JPEG, JPG, AVIF, JXL and ANY)
tinify.fromFile("panda-sticker.jpg")
.convert({type: tinify.Format.JXL})
.toFile("panda-sticker.jxl");
// Pass several and the API returns the smallest result
tinify.fromFile("panda-sticker.jpg")
.convert({type: [tinify.Format.JXL, tinify.Format.WEBP]})
.toFile("panda-sticker.min");Two things worth your call before merge:
|
Adds a Format constant object so the media types accepted by convert() are discoverable at runtime as well as in the type system, matching the other Tinify client libraries and including JPEG XL (image/jxl), which the API already accepts. SupportedImageTypes is now derived from Format rather than duplicating the literal list, so the two cannot drift apart. The derived union is equivalent to the old one: it still rejects unknown media types and still excludes the "*/*" wildcard from array form. That equivalence is enforced by @ts-expect-error assertions rather than asserted in prose -- an unfired @ts-expect-error is itself a compile error, so they cannot rot. JPG documents image/jpg as the alternative spelling the API also accepts. It normalises to image/jpeg before conversion, so the two constants hold different strings but select the same format. Adds a README example and bumps to 1.9.0, promoting the changelog entry out of Unreleased.
65aafc8 to
2257f35
Compare
Adds a
tinify.Formatconstant object so the media types accepted byconvertare discoverable at runtime, not only in the type system — matching the
FormatAPI being added to the other five Tinify client libraries.JXL itself already landed here in 1.8.3 (
ea25ea9); this PR is about making thefull set discoverable and consistent across languages.
Members
WEBP,PNG,JPEG,JPG,AVIF,JXL,ANY(*/*) — mirroring the APIallowlist exactly.
SupportedImageTypesis now derived fromFormatRather than duplicating the literal list, the union is computed from the
constant object, so the two cannot drift apart:
The derived union is equivalent to the old one, verified with a negative
typecheck: it still rejects unknown media types, and still excludes the
*/*wildcard from the array form. Both
@ts-expect-errorassertions fired:Verification
Full suite green locally:
npm test→ 85 passing, and the typing test compileswith the new
tinify.Format.*cases added to it.Note on the remote
This branch was pushed to
upstream(tinify/tinify-nodejs), since the localcheckout's
originpoints at a personal fork whilemastertracksupstream.Part of a coordinated change across all six Tinify client libraries, so the same
FormatAPI is available in each.