Skip to content

Commit 90d07c2

Browse files
authored
fix: remove applyWhen in favor of explicit props overlap check with alwaysApply exception (#228)
# Description <!-- Include a summary of the change made and also list the dependencies that are required if any --> Simplify applyWhen to just check for presence of props from the new props key as discussed with @colbyfayock, add an alwaysApply key that can be used for exceptions like SanitizePlugin that should always run regardless of the presence of associated keys. This is a rebased version of #226. ## Issue Ticket Number Fixes #<ISSUE_NUMBER> <!-- Specify above which issue this fixes by referencing the issue number (`#<ISSUE_NUMBER>`) or issue URL. --> <!-- Example: Fixes https://github.com/colbyfayock/cloudinary-util/issues/<ISSUE_NUMBER> --> ## Type of change <!-- Please select all options that are applicable. --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Fix or improve the documentation - [ ] This change requires a documentation update # Checklist <!-- These must all be followed and checked. --> - [ ] I have followed the contributing guidelines of this project as mentioned in [CONTRIBUTING.md](/CONTRIBUTING.md) - [ ] I have created an [issue](https://github.com/colbyfayock/cloudinary-util/issues) ticket for this PR - [ ] I have checked to ensure there aren't other open [Pull Requests](https://github.com/colbyfayock/cloudinary-util/pulls) for the same update/change? - [ ] I have performed a self-review of my own code - [ ] I have run tests locally to ensure they all pass - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes needed to the documentation
1 parent 23e9afd commit 90d07c2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+318
-3413
lines changed

docs/src/components/SchemaTable/SchemaTable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export const SchemaTable = ({ schema, schemaKey }) => {
5959
};
6060

6161
return property;
62-
}
62+
},
6363
);
6464

6565
const sortedProperties = sortByKey(formattedProperties, "name");

packages/types/CHANGELOG.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
# [@cloudinary-util/types-v2.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v2.0.0-beta.1...@cloudinary-util/types-v2.0.0-beta.2) (2024-10-22)
22

3-
43
### Bug Fixes
54

6-
* Add TypeScript Types for Cloudinary Product Gallery Widget ([#218](https://github.com/cloudinary-community/cloudinary-util/issues/218)) ([05cd33e](https://github.com/cloudinary-community/cloudinary-util/commit/05cd33e3948d486ac87600b798e0006789e2d914)), closes [#199](https://github.com/cloudinary-community/cloudinary-util/issues/199)
5+
- Add TypeScript Types for Cloudinary Product Gallery Widget ([#218](https://github.com/cloudinary-community/cloudinary-util/issues/218)) ([05cd33e](https://github.com/cloudinary-community/cloudinary-util/commit/05cd33e3948d486ac87600b798e0006789e2d914)), closes [#199](https://github.com/cloudinary-community/cloudinary-util/issues/199)
76

87
# [@cloudinary-util/types-v2.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.11...@cloudinary-util/types-v2.0.0-beta.1) (2024-10-18)
98

10-
119
### Features
1210

13-
* migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481))
11+
- migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481))
1412

1513
# [@cloudinary-util/types-v1.5.11](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.10...@cloudinary-util/types-v1.5.11) (2024-10-07)
1614

packages/url-loader/CHANGELOG.md

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,39 @@
11
# [@cloudinary-util/url-loader-v6.0.0-beta.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.4...@cloudinary-util/url-loader-v6.0.0-beta.5) (2024-10-31)
22

3-
43
### Bug Fixes
54

6-
* make plugins and cloudinaryPluginProps tree-shakeable ([#227](https://github.com/cloudinary-community/cloudinary-util/issues/227)) ([163cb2f](https://github.com/cloudinary-community/cloudinary-util/commit/163cb2fdd05c7a3444cfb22edade79891f25ffd3))
5+
- make plugins and cloudinaryPluginProps tree-shakeable ([#227](https://github.com/cloudinary-community/cloudinary-util/issues/227)) ([163cb2f](https://github.com/cloudinary-community/cloudinary-util/commit/163cb2fdd05c7a3444cfb22edade79891f25ffd3))
76

87
# [@cloudinary-util/url-loader-v6.0.0-beta.4](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.3...@cloudinary-util/url-loader-v6.0.0-beta.4) (2024-10-25)
98

10-
119
### Bug Fixes
1210

13-
* adding applyWhen to streaming profile to prevent abr plugin from running ([ef7e57a](https://github.com/cloudinary-community/cloudinary-util/commit/ef7e57adc03afb0e08ebf2bb0053d34c12054523))
14-
* adding string and number back to replaceBackground ([672009a](https://github.com/cloudinary-community/cloudinary-util/commit/672009afb7797c540c0a6fdc31115f0c245ed8b2))
11+
- adding applyWhen to streaming profile to prevent abr plugin from running ([ef7e57a](https://github.com/cloudinary-community/cloudinary-util/commit/ef7e57adc03afb0e08ebf2bb0053d34c12054523))
12+
- adding string and number back to replaceBackground ([672009a](https://github.com/cloudinary-community/cloudinary-util/commit/672009afb7797c540c0a6fdc31115f0c245ed8b2))
1513

1614
# [@cloudinary-util/url-loader-v6.0.0-beta.3](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.2...@cloudinary-util/url-loader-v6.0.0-beta.3) (2024-10-24)
1715

18-
1916
### Features
2017

21-
* enumerate plugin props ([#224](https://github.com/cloudinary-community/cloudinary-util/issues/224)) ([731d545](https://github.com/cloudinary-community/cloudinary-util/commit/731d54511741f9bb56fc6b1d6e978a8f21d88082))
18+
- enumerate plugin props ([#224](https://github.com/cloudinary-community/cloudinary-util/issues/224)) ([731d545](https://github.com/cloudinary-community/cloudinary-util/commit/731d54511741f9bb56fc6b1d6e978a8f21d88082))
2219

2320
# [@cloudinary-util/url-loader-v6.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.1...@cloudinary-util/url-loader-v6.0.0-beta.2) (2024-10-22)
2421

25-
2622
### Bug Fixes
2723

28-
* Add enum for format parameter ([#220](https://github.com/cloudinary-community/cloudinary-util/issues/220)) ([0ecd331](https://github.com/cloudinary-community/cloudinary-util/commit/0ecd331e1bfe9244bedc82fc8d61e228bdc00d4c)), closes [#142](https://github.com/cloudinary-community/cloudinary-util/issues/142)
24+
- Add enum for format parameter ([#220](https://github.com/cloudinary-community/cloudinary-util/issues/220)) ([0ecd331](https://github.com/cloudinary-community/cloudinary-util/commit/0ecd331e1bfe9244bedc82fc8d61e228bdc00d4c)), closes [#142](https://github.com/cloudinary-community/cloudinary-util/issues/142)
2925

3026
# [@cloudinary-util/url-loader-v6.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.5...@cloudinary-util/url-loader-v6.0.0-beta.1) (2024-10-18)
3127

3228
### Features
3329

34-
* migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481))
30+
- migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481))
3531

3632
# [@cloudinary-util/url-loader-v5.10.6](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.5...@cloudinary-util/url-loader-v5.10.6) (2024-10-22)
3733

3834
### Bug Fixes
3935

40-
* Add enum for format parameter ([#220](https://github.com/cloudinary-community/cloudinary-util/issues/220)) ([0ecd331](https://github.com/cloudinary-community/cloudinary-util/commit/0ecd331e1bfe9244bedc82fc8d61e228bdc00d4c)), closes [#142](https://github.com/cloudinary-community/cloudinary-util/issues/142)
36+
- Add enum for format parameter ([#220](https://github.com/cloudinary-community/cloudinary-util/issues/220)) ([0ecd331](https://github.com/cloudinary-community/cloudinary-util/commit/0ecd331e1bfe9244bedc82fc8d61e228bdc00d4c)), closes [#142](https://github.com/cloudinary-community/cloudinary-util/issues/142)
4137

4238
# [@cloudinary-util/url-loader-v5.10.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.4...@cloudinary-util/url-loader-v5.10.5) (2024-10-07)
4339

packages/url-loader/src/lib/cloudinary.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import type { PluginOptions, PluginResults } from "../types/plugins.js";
4040
import type { VideoOptions } from "../types/video.js";
4141
import type {
4242
CloudinaryKey,
43-
OptionsFor,
43+
CtxParam,
4444
TransformationPlugin,
4545
} from "./plugin.js";
4646
import { entriesOf, throwError } from "./utils.js";
@@ -135,7 +135,7 @@ export interface ConstructUrlProps<
135135
*/
136136
config?: ConfigOptions;
137137
// prioritize inferring assetType so available options can be derived from it
138-
options: { assetType?: assetType } & OptionsFor<assetType>;
138+
options: { assetType?: assetType } & CtxParam<assetType>;
139139
}
140140

141141
export type CldAsset = CloudinaryImage | CloudinaryVideo;
@@ -214,12 +214,10 @@ export function constructCloudinaryUrl<
214214
const pluginEffects: PluginOptions = {};
215215

216216
transformationPlugins.forEach(
217-
({ name, apply, strict, applyWhen, supports }: TransformationPlugin) => {
218-
const shouldApply =
219-
applyWhen === undefined ||
220-
(typeof applyWhen === "string"
221-
? options[applyWhen as never] !== undefined
222-
: applyWhen(options));
217+
({ name, apply, strict, supports, props }: TransformationPlugin) => {
218+
const shouldApply = Object.keys(props).some(
219+
(key) => options[key as never] !== undefined
220+
);
223221

224222
if (!shouldApply) return;
225223

@@ -235,6 +233,9 @@ export function constructCloudinaryUrl<
235233
return;
236234
}
237235

236+
// we're actually passing options for both opts and ctx, but
237+
// the second param is typed to only include the options
238+
// declared by the plugin's `inferOwnOptions`
238239
const results: PluginResults = apply(cldAsset, options);
239240

240241
const pluginOptions = results?.options ?? {};

packages/url-loader/src/lib/plugin.ts

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,59 +18,89 @@ export type AlwaysApply = () => true;
1818

1919
export interface PluginDefinition<
2020
assetType extends SupportedAssetType,
21-
when extends ApplyWhen,
2221
name extends string,
2322
options extends object,
23+
alwaysApply extends boolean,
2424
> {
2525
name: name;
2626
supports: assetType;
27-
apply: PluginApplication<assetType, when>;
27+
apply: PluginApplicationDefinition<assetType, options, alwaysApply>;
2828
inferOwnOptions: options;
2929
props: Record<keyof options, true>;
30-
applyWhen?: when | undefined;
30+
alwaysApply?: alwaysApply;
3131
strict?: boolean;
3232
}
3333

3434
export interface TransformationPlugin<
3535
assetType extends SupportedAssetType = SupportedAssetType,
36-
when extends ApplyWhen = ApplyWhen,
3736
name extends string = string,
38-
options extends object = object,
37+
opts extends object = object,
38+
alwaysApply extends boolean = boolean,
3939
> {
4040
name: name;
4141
supports: assetType;
42-
apply: PluginApplication<assetType, when>;
43-
inferOwnOptions: options;
44-
props: Record<keyof options, true>;
45-
applyWhen?: when | undefined;
42+
apply: PluginApplication<assetType, opts, alwaysApply>;
43+
inferOwnOptions: opts;
44+
props: Record<keyof opts, true>;
45+
alwaysApply: alwaysApply;
4646
strict?: boolean;
4747
}
4848

49-
export type OptionsFor<
50-
assetType extends SupportedAssetTypeInput,
51-
when extends ApplyWhen = AlwaysApply,
52-
options = assetType extends "all"
49+
export type OwnOptionsParam<
50+
opts extends object,
51+
alwaysApply extends boolean,
52+
> = opts &
53+
// if there's only one owned key, we know it must be present if
54+
// apply is being invoked, so require it so we don't have to recheck
55+
// in the implementation unless alwaysApply is true
56+
([alwaysApply] extends [true]
57+
? {}
58+
: { [k in singleKeyOf<opts>]: Exclude<opts[k], undefined> });
59+
60+
export type CtxParam<assetType extends SupportedAssetTypeInput> =
61+
assetType extends "all"
5362
? AllOptions
5463
: assetType extends "video" | "videos"
5564
? VideoOptions
56-
: ImageOptions,
57-
> = [when] extends [keyof options]
58-
? // if the plugin applies based on a single key being defined, we know it will be
59-
// present in the options passed to apply
60-
options & { [k in when]: {} }
61-
: options;
65+
: ImageOptions;
66+
67+
// extract the key if there is exactly one, otherwise never
68+
type singleKeyOf<opts> = {
69+
[k in keyof opts]: keyof opts extends k ? k : never;
70+
}[keyof opts];
71+
72+
export type PluginApplicationDefinition<
73+
assetType extends SupportedAssetType,
74+
opts extends object,
75+
alwaysApply extends boolean,
76+
> = (
77+
cldAsset: CldAsset,
78+
/** Options owned by this plugin */
79+
opts: OwnOptionsParam<opts, alwaysApply>,
80+
ctx: CtxParam<assetType>,
81+
) => PluginResults;
6282

6383
export type PluginApplication<
6484
assetType extends SupportedAssetType,
65-
when extends ApplyWhen = AlwaysApply,
66-
> = (cldAsset: CldAsset, options: OptionsFor<assetType, when>) => PluginResults;
85+
opts extends object,
86+
alwaysApply extends boolean,
87+
> = (
88+
cldAsset: CldAsset,
89+
// externally, we want the wider assetType options as well
90+
opts: OwnOptionsParam<opts, alwaysApply> & CtxParam<assetType>,
91+
) => PluginResults;
6792

6893
export const plugin = <
6994
asset extends SupportedAssetType,
70-
when extends ApplyWhen,
7195
name extends string,
72-
options extends object,
96+
opts extends object,
97+
alwaysApply extends boolean,
7398
>(
74-
def: PluginDefinition<asset, when, name, options>
75-
): TransformationPlugin<asset, when, name, options> =>
76-
({ strict: false, ...def }) as never;
99+
def: PluginDefinition<asset, name, opts, alwaysApply>,
100+
): TransformationPlugin<asset, name, opts, alwaysApply> =>
101+
({
102+
strict: false,
103+
alwaysApply: false,
104+
...def,
105+
apply: (cldAsset, ctx) => def.apply(cldAsset, ctx as never, ctx as never),
106+
}) satisfies TransformationPlugin as never;

packages/url-loader/src/lib/upload.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ export function generateSignatureCallback({
1414
}: GenerateSignatureCallback) {
1515
return function generateSignature(
1616
callback: (signature: string | null, error?: unknown) => void,
17-
paramsToSign: object
17+
paramsToSign: object,
1818
) {
1919
if (typeof signatureEndpoint === "undefined") {
2020
throw Error(
21-
"Failed to generate signature: signatureEndpoint property undefined."
21+
"Failed to generate signature: signatureEndpoint property undefined.",
2222
);
2323
}
2424

packages/url-loader/src/lib/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const entriesOf: <o extends object>(o: o) => entryOf<o>[] =
3333
*/
3434
export const throwError: (
3535
message: string,
36-
ctor?: new (message: string) => Error
36+
ctor?: new (message: string) => Error,
3737
) => never = (message, ctor = Error) => {
3838
throw new ctor(message);
3939
};

packages/url-loader/src/lib/video-player.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export interface GetVideoPlayerOptionsLogo {
3838

3939
export function getVideoPlayerOptions(
4040
options: GetVideoPlayerOptions,
41-
config: CloudinaryAssetConfiguration
41+
config: CloudinaryAssetConfiguration,
4242
) {
4343
const {
4444
autoplay,
@@ -63,7 +63,7 @@ export function getVideoPlayerOptions(
6363

6464
if (!cloudName) {
6565
throw new Error(
66-
"A Cloudinary Cloud name is required, please make sure your environment variable is set and configured in your environment."
66+
"A Cloudinary Cloud name is required, please make sure your environment variable is set and configured in your environment.",
6767
);
6868
}
6969

@@ -85,7 +85,7 @@ export function getVideoPlayerOptions(
8585

8686
if (!publicId) {
8787
throw new Error(
88-
"Video Player requires a src, please make sure to configure your src as a public ID or Cloudinary URL."
88+
"Video Player requires a src, please make sure to configure your src as a public ID or Cloudinary URL.",
8989
);
9090
}
9191

packages/url-loader/src/plugins/abr.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@ export const AbrPlugin = plugin({
1414
name: "Abr",
1515
supports: "video",
1616
inferOwnOptions: {} as AbrPlugin.Options,
17-
applyWhen: 'streamingProfile',
1817
props: {
1918
streamingProfile: true,
2019
},
2120
apply: (asset, opts) => {
22-
if (typeof opts.streamingProfile === "string") {
23-
asset.addTransformation(`sp_${opts.streamingProfile}`);
24-
}
21+
if (typeof opts.streamingProfile !== "string") return {};
22+
23+
asset.addTransformation(`sp_${opts.streamingProfile}`);
2524

2625
return {};
2726
},

packages/url-loader/src/plugins/cropping.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ export declare namespace CroppingPlugin {
2525
crop?: CropMode | NestedOptions | ReadonlyArray<NestedOptions>;
2626
gravity?: Gravity;
2727
zoom?: Zoom;
28+
/**
29+
* @description Height of the given asset.
30+
*/
31+
height?: string | number;
32+
/**
33+
* @description Width of the given asset.
34+
*/
35+
width?: string | number;
2836
}
2937

3038
export interface NestedOptions {
@@ -49,6 +57,8 @@ export const CroppingPlugin = plugin({
4957
crop: true,
5058
gravity: true,
5159
zoom: true,
60+
height: true,
61+
width: true,
5262
},
5363
// crop is applied even if the crop key is undefined
5464
apply: (asset, opts) => {

0 commit comments

Comments
 (0)