Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: remove applyWhen in favor of explicit props overlap check with alwaysApply exception #228

Merged
merged 4 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/src/components/SchemaTable/SchemaTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const SchemaTable = ({ schema, schemaKey }) => {
};

return property;
}
},
);

const sortedProperties = sortByKey(formattedProperties, "name");
Expand Down
6 changes: 2 additions & 4 deletions packages/types/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
# [@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)


### Bug Fixes

* 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)
- 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)

# [@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)


### Features

* 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))
- 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))

# [@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)

Expand Down
18 changes: 7 additions & 11 deletions packages/url-loader/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,39 @@
# [@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)


### Bug Fixes

* 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))
- 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))

# [@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)


### Bug Fixes

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

# [@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)


### Features

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

# [@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)


### Bug Fixes

* 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)
- 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)

# [@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)

### Features

* 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))
- 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))

# [@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)

### Bug Fixes

* 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)
- 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)

# [@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)

Expand Down
17 changes: 9 additions & 8 deletions packages/url-loader/src/lib/cloudinary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import type { PluginOptions, PluginResults } from "../types/plugins.js";
import type { VideoOptions } from "../types/video.js";
import type {
CloudinaryKey,
OptionsFor,
CtxParam,
TransformationPlugin,
} from "./plugin.js";
import { entriesOf, throwError } from "./utils.js";
Expand Down Expand Up @@ -135,7 +135,7 @@ export interface ConstructUrlProps<
*/
config?: ConfigOptions;
// prioritize inferring assetType so available options can be derived from it
options: { assetType?: assetType } & OptionsFor<assetType>;
options: { assetType?: assetType } & CtxParam<assetType>;
}

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

transformationPlugins.forEach(
({ name, apply, strict, applyWhen, supports }: TransformationPlugin) => {
const shouldApply =
applyWhen === undefined ||
(typeof applyWhen === "string"
? options[applyWhen as never] !== undefined
: applyWhen(options));
({ name, apply, strict, supports, props }: TransformationPlugin) => {
const shouldApply = Object.keys(props).some(
(key) => options[key as never] !== undefined
);

if (!shouldApply) return;

Expand All @@ -235,6 +233,9 @@ export function constructCloudinaryUrl<
return;
}

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

const pluginOptions = results?.options ?? {};
Expand Down
82 changes: 56 additions & 26 deletions packages/url-loader/src/lib/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,59 +18,89 @@ export type AlwaysApply = () => true;

export interface PluginDefinition<
assetType extends SupportedAssetType,
when extends ApplyWhen,
name extends string,
options extends object,
alwaysApply extends boolean,
> {
name: name;
supports: assetType;
apply: PluginApplication<assetType, when>;
apply: PluginApplicationDefinition<assetType, options, alwaysApply>;
inferOwnOptions: options;
props: Record<keyof options, true>;
applyWhen?: when | undefined;
alwaysApply?: alwaysApply;
strict?: boolean;
}

export interface TransformationPlugin<
assetType extends SupportedAssetType = SupportedAssetType,
when extends ApplyWhen = ApplyWhen,
name extends string = string,
options extends object = object,
opts extends object = object,
alwaysApply extends boolean = boolean,
> {
name: name;
supports: assetType;
apply: PluginApplication<assetType, when>;
inferOwnOptions: options;
props: Record<keyof options, true>;
applyWhen?: when | undefined;
apply: PluginApplication<assetType, opts, alwaysApply>;
inferOwnOptions: opts;
props: Record<keyof opts, true>;
alwaysApply: alwaysApply;
strict?: boolean;
}

export type OptionsFor<
assetType extends SupportedAssetTypeInput,
when extends ApplyWhen = AlwaysApply,
options = assetType extends "all"
export type OwnOptionsParam<
opts extends object,
alwaysApply extends boolean,
> = opts &
// if there's only one owned key, we know it must be present if
// apply is being invoked, so require it so we don't have to recheck
// in the implementation unless alwaysApply is true
([alwaysApply] extends [true]
? {}
: { [k in singleKeyOf<opts>]: Exclude<opts[k], undefined> });

export type CtxParam<assetType extends SupportedAssetTypeInput> =
assetType extends "all"
? AllOptions
: assetType extends "video" | "videos"
? VideoOptions
: ImageOptions,
> = [when] extends [keyof options]
? // if the plugin applies based on a single key being defined, we know it will be
// present in the options passed to apply
options & { [k in when]: {} }
: options;
: ImageOptions;

// extract the key if there is exactly one, otherwise never
type singleKeyOf<opts> = {
[k in keyof opts]: keyof opts extends k ? k : never;
}[keyof opts];

export type PluginApplicationDefinition<
assetType extends SupportedAssetType,
opts extends object,
alwaysApply extends boolean,
> = (
cldAsset: CldAsset,
/** Options owned by this plugin */
opts: OwnOptionsParam<opts, alwaysApply>,
ctx: CtxParam<assetType>,
) => PluginResults;

export type PluginApplication<
assetType extends SupportedAssetType,
when extends ApplyWhen = AlwaysApply,
> = (cldAsset: CldAsset, options: OptionsFor<assetType, when>) => PluginResults;
opts extends object,
alwaysApply extends boolean,
> = (
cldAsset: CldAsset,
// externally, we want the wider assetType options as well
opts: OwnOptionsParam<opts, alwaysApply> & CtxParam<assetType>,
) => PluginResults;

export const plugin = <
asset extends SupportedAssetType,
when extends ApplyWhen,
name extends string,
options extends object,
opts extends object,
alwaysApply extends boolean,
>(
def: PluginDefinition<asset, when, name, options>
): TransformationPlugin<asset, when, name, options> =>
({ strict: false, ...def }) as never;
def: PluginDefinition<asset, name, opts, alwaysApply>,
): TransformationPlugin<asset, name, opts, alwaysApply> =>
({
strict: false,
alwaysApply: false,
...def,
apply: (cldAsset, ctx) => def.apply(cldAsset, ctx as never, ctx as never),
}) satisfies TransformationPlugin as never;
4 changes: 2 additions & 2 deletions packages/url-loader/src/lib/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export function generateSignatureCallback({
}: GenerateSignatureCallback) {
return function generateSignature(
callback: (signature: string | null, error?: unknown) => void,
paramsToSign: object
paramsToSign: object,
) {
if (typeof signatureEndpoint === "undefined") {
throw Error(
"Failed to generate signature: signatureEndpoint property undefined."
"Failed to generate signature: signatureEndpoint property undefined.",
);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/url-loader/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const entriesOf: <o extends object>(o: o) => entryOf<o>[] =
*/
export const throwError: (
message: string,
ctor?: new (message: string) => Error
ctor?: new (message: string) => Error,
) => never = (message, ctor = Error) => {
throw new ctor(message);
};
Expand Down
6 changes: 3 additions & 3 deletions packages/url-loader/src/lib/video-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export interface GetVideoPlayerOptionsLogo {

export function getVideoPlayerOptions(
options: GetVideoPlayerOptions,
config: CloudinaryAssetConfiguration
config: CloudinaryAssetConfiguration,
) {
const {
autoplay,
Expand All @@ -63,7 +63,7 @@ export function getVideoPlayerOptions(

if (!cloudName) {
throw new Error(
"A Cloudinary Cloud name is required, please make sure your environment variable is set and configured in your environment."
"A Cloudinary Cloud name is required, please make sure your environment variable is set and configured in your environment.",
);
}

Expand All @@ -85,7 +85,7 @@ export function getVideoPlayerOptions(

if (!publicId) {
throw new Error(
"Video Player requires a src, please make sure to configure your src as a public ID or Cloudinary URL."
"Video Player requires a src, please make sure to configure your src as a public ID or Cloudinary URL.",
);
}

Expand Down
7 changes: 3 additions & 4 deletions packages/url-loader/src/plugins/abr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ export const AbrPlugin = plugin({
name: "Abr",
supports: "video",
inferOwnOptions: {} as AbrPlugin.Options,
applyWhen: 'streamingProfile',
props: {
streamingProfile: true,
},
apply: (asset, opts) => {
if (typeof opts.streamingProfile === "string") {
asset.addTransformation(`sp_${opts.streamingProfile}`);
}
if (typeof opts.streamingProfile !== "string") return {};

asset.addTransformation(`sp_${opts.streamingProfile}`);

return {};
},
Expand Down
10 changes: 10 additions & 0 deletions packages/url-loader/src/plugins/cropping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ export declare namespace CroppingPlugin {
crop?: CropMode | NestedOptions | ReadonlyArray<NestedOptions>;
gravity?: Gravity;
zoom?: Zoom;
/**
* @description Height of the given asset.
*/
height?: string | number;
/**
* @description Width of the given asset.
*/
width?: string | number;
}

export interface NestedOptions {
Expand All @@ -49,6 +57,8 @@ export const CroppingPlugin = plugin({
crop: true,
gravity: true,
zoom: true,
height: true,
width: true,
},
// crop is applied even if the crop key is undefined
apply: (asset, opts) => {
Expand Down
16 changes: 8 additions & 8 deletions packages/url-loader/src/plugins/default-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ export const DefaultImagePlugin = plugin({
apply: (asset, opts) => {
const { defaultImage } = opts;

if (typeof defaultImage === "string") {
if (!getFormat(defaultImage)) {
console.warn(
`The defaultImage prop may be missing a format and must include it along with the public ID. (Ex: myimage.jpg)`
);
}
const defaultImageId = defaultImage.replace(/\//g, ":");
asset.addTransformation(`d_${defaultImageId}`);
if (typeof defaultImage !== "string") return {};

if (!getFormat(defaultImage)) {
console.warn(
`The defaultImage prop may be missing a format and must include it along with the public ID. (Ex: myimage.jpg)`
);
}
const defaultImageId = defaultImage.replace(/\//g, ":");
asset.addTransformation(`d_${defaultImageId}`);

return {};
},
Expand Down
10 changes: 5 additions & 5 deletions packages/url-loader/src/plugins/effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ export const EffectsPlugin = plugin({
vignette: true,
effects: true,
},
apply: (cldAsset, options) => {
apply: (cldAsset, opts) => {
// Handle any top-level effect props

const transformationStrings = constructTransformationString({
effects: qualifiersEffects,
options,
options: opts,
});

transformationStrings.forEach((transformation) => {
Expand All @@ -93,8 +93,8 @@ export const EffectsPlugin = plugin({
// If we're passing in an effects prop explicitly, treat it as an array of
// effects that we need to process

if (isArray(options?.effects)) {
options?.effects.forEach((effectsSet) => {
if (isArray(opts?.effects)) {
opts?.effects.forEach((effectsSet) => {
const transformationString = constructTransformationString({
effects: qualifiersEffects,
options: effectsSet,
Expand Down Expand Up @@ -123,7 +123,7 @@ export const EffectsPlugin = plugin({
value: options?.[key],
converters,
});
}
},
);
}

Expand Down
Loading