DEV: Added value transformers that mutate the value instead of returning it (#29537)

This commit is contained in:
Sérgio Saquetim 2024-11-01 14:23:46 -03:00 committed by GitHub
parent 723dc1fa55
commit 4863b2ab7e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 100 additions and 8 deletions

View File

@ -279,15 +279,22 @@ export function applyBehaviorTransformer(
}
/**
* Apply a transformer to a value
* Apply a transformer to a value.
*
* @param {string} transformerName the name of the transformer applied
* @param {*} defaultValue the default value
* @param {*} [context] the optional context to pass to the transformer callbacks.
*
* @returns {*} the transformed value
* @param {string} transformerName - The name of the transformer applied
* @param {*} defaultValue - The default value
* @param {*} [context] - The optional context to pass to the transformer callbacks
* @param {Object} [opts] - Options for the transformer
* @param {boolean} [opts.mutable] - Flag indicating if the value should be mutated instead of returned
* @returns {*} The transformed value
* @throws {Error} If the transformer name does not exist or the context is invalid
*/
export function applyValueTransformer(transformerName, defaultValue, context) {
export function applyValueTransformer(
transformerName,
defaultValue,
context,
opts = { mutable: false }
) {
const normalizedTransformerName = _normalizeTransformerName(
transformerName,
transformerTypes.VALUE
@ -321,6 +328,7 @@ export function applyValueTransformer(transformerName, defaultValue, context) {
return defaultValue;
}
const mutable = opts?.mutable; // flag indicating if the value should be mutated instead of returned
let newValue = defaultValue;
const transformerPoolSize = transformers.length;
@ -328,7 +336,17 @@ export function applyValueTransformer(transformerName, defaultValue, context) {
const valueCallback = transformers[i];
try {
newValue = valueCallback({ value: newValue, context });
const value = valueCallback({ value: newValue, context });
if (mutable && typeof value !== "undefined") {
// eslint-disable-next-line no-console
throw new Error(
`${prefix}: transformer "${transformerName}" expects the value to be mutated instead of returned. Remove the return value in your transformer.`
);
}
if (!mutable) {
newValue = value;
}
} catch (error) {
document.dispatchEvent(
new CustomEvent("discourse-error", {
@ -345,6 +363,26 @@ export function applyValueTransformer(transformerName, defaultValue, context) {
return newValue;
}
/**
* Apply a transformer to a mutable value.
* The registered transformers should mutate the value instead of returning it.
*
* @param {string} transformerName - The name of the transformer applied
* @param {*} defaultValue - The default value
* @param {*} [context] - The optional context to pass to the transformer callbacks
* @returns {*} The transformed value
* @throws {Error} If the transformer name does not exist or the context is invalid
*/
export function applyMutableValueTransformer(
transformerName,
defaultValue,
context
) {
return applyValueTransformer(transformerName, defaultValue, context, {
mutable: true,
});
}
/**
* @typedef {Object} TransformerInfo
* @property {string} name - The normalized name of the transformer

View File

@ -7,6 +7,7 @@ import {
acceptNewTransformerNames,
acceptTransformerRegistrations,
applyBehaviorTransformer,
applyMutableValueTransformer,
applyValueTransformer,
disableThrowingApplyExceptionOnTests,
transformerTypes,
@ -292,6 +293,7 @@ module("Unit | Utility | transformers", function (hooks) {
);
class Testable {}
assert.throws(
() =>
applyValueTransformer(
@ -500,6 +502,57 @@ module("Unit | Utility | transformers", function (hooks) {
});
});
module("applyMutableValueTransformer", function (innerHooks) {
innerHooks.beforeEach(function () {
acceptNewTransformerNames();
withPluginApi("1.34.0", (api) => {
api.addValueTransformerName("test-mutable-transformer");
});
acceptTransformerRegistrations();
});
test("mutates the value as expected", function (assert) {
withPluginApi("1.34.0", (api) => {
api.registerValueTransformer(
"test-mutable-transformer",
({ value }) => {
value.mutate();
}
);
});
let mutated = false;
const value = {
mutate() {
mutated = true;
},
};
applyMutableValueTransformer("test-mutable-transformer", value);
assert.strictEqual(mutated, true, "the value was mutated");
});
test("raises an exception if the transformer returns a value different from undefined", function (assert) {
assert.throws(
() => {
withPluginApi("1.34.0", (api) => {
api.registerValueTransformer(
"test-mutable-transformer",
() => "unexpected value"
);
});
applyMutableValueTransformer(
"test-mutable-transformer",
"default value"
);
},
/expects the value to be mutated instead of returned. Remove the return value in your transformer./,
"logs warning to the console when the transformer returns a value different from undefined"
);
});
});
module("pluginApi.addBehaviorTransformerName", function (innerHooks) {
innerHooks.beforeEach(function () {
this.consoleWarnStub = sinon.stub(console, "warn");
@ -816,6 +869,7 @@ module("Unit | Utility | transformers", function (hooks) {
);
class Testable {}
assert.throws(
() =>
applyBehaviorTransformer(