From 9d97cc6e4c091808e5345a5a5970319ae1d24a07 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Thu, 5 Mar 2026 15:49:51 +0000 Subject: [PATCH] fix(transform): Fix transform for stage not using name for selection #481 --- src/backend/common/AbstractComponent.ts | 6 +- .../common/transforms/TransformerManager.ts | 14 +++- .../tests/component/transformers.test.ts | 77 ++++++++++++++++++- 3 files changed, 89 insertions(+), 8 deletions(-) diff --git a/src/backend/common/AbstractComponent.ts b/src/backend/common/AbstractComponent.ts index bdcbd41a..3e98499c 100644 --- a/src/backend/common/AbstractComponent.ts +++ b/src/backend/common/AbstractComponent.ts @@ -32,6 +32,8 @@ import ConsoleFormatter from "jsondiffpatch/formatters/console"; const console = new ConsoleFormatter(); +export type AbstractComponentConfig = (CommonClientConfig | CommonSourceConfig) & { transformManager?: TransformerManager }; + export default abstract class AbstractComponent extends AbstractInitializable { declare config: CommonClientConfig | CommonSourceConfig; @@ -41,9 +43,9 @@ export default abstract class AbstractComponent extends AbstractInitializable { protected transformManager: TransformerManager; protected cache: MSCache; - protected constructor(config: CommonClientConfig | CommonSourceConfig) { + protected constructor(config: AbstractComponentConfig) { super(config); - this.transformManager = getRoot().items.transformerManager; + this.transformManager = config.transformManager ?? getRoot().items.transformerManager; this.cache = getRoot().items.cache(); } diff --git a/src/backend/common/transforms/TransformerManager.ts b/src/backend/common/transforms/TransformerManager.ts index c4ea89d1..319eb0e4 100644 --- a/src/backend/common/transforms/TransformerManager.ts +++ b/src/backend/common/transforms/TransformerManager.ts @@ -116,9 +116,17 @@ export default class TransformerManager { throw new Error(`No transformer of type '${data.type}' is registered.`); } - if (list.length > 1 && (data as any).name === undefined) { - this.logger.warn(`More than one '${data.type}' transformer but name was not specified, using first registered`); - return list[0]; + if (list.length > 1) { + if(data.name === undefined) { + this.logger.warn(`More than one '${data.type}' transformer but name was not specified, using first registered`); + return list[0]; + } else { + const namedTransformers = list.find(x => x.name.toLocaleLowerCase().trim() === data.name.toLocaleLowerCase().trim()); + if(namedTransformers === undefined) { + throw new SimpleError(`Component wanted transformer type ${data.type} with name ${data.name}. Transforms of this type are registered but none have this name.`); + } + return namedTransformers; + } } else { return list[0] } diff --git a/src/backend/tests/component/transformers.test.ts b/src/backend/tests/component/transformers.test.ts index d3f6cf38..8dc037a5 100644 --- a/src/backend/tests/component/transformers.test.ts +++ b/src/backend/tests/component/transformers.test.ts @@ -2,7 +2,7 @@ import { loggerTest, loggerDebug, childLogger } from "@foxxmd/logging"; import chai, { assert, expect } from 'chai'; import asPromised from 'chai-as-promised'; import { after, before, describe, it } from 'mocha'; -import AbstractComponent from "../../common/AbstractComponent.js"; +import AbstractComponent, { AbstractComponentConfig } from "../../common/AbstractComponent.js"; import { ConditionalSearchAndReplaceRegExp, STAGE_TYPES, STAGE_TYPES_METADATA, STAGE_TYPES_USER, TRANSFORM_HOOK } from "../../common/infrastructure/Transform.js"; @@ -13,6 +13,9 @@ import { findCauseByMessage } from "../../utils/ErrorUtils.js"; import NativeTransformer from "../../common/transforms/NativeTransformer.js"; import { initMemoryCache } from "../../common/Cache.js"; import { Cacheable } from "cacheable"; +import { TransformerCommonConfig } from "../../../core/Atomic.js"; +import TransformerManager from "../../common/transforms/TransformerManager.js"; +import { transientCache } from "../utils/CacheTestUtils.js"; chai.use(asPromised); @@ -23,11 +26,17 @@ class TestComponent extends AbstractComponent { protected getIdentifier(): string { return 'test'; } - constructor() { - super({}); + constructor(config?: AbstractComponentConfig) { + super(config ?? {}); } } +const createTestComponent = (config?: AbstractComponentConfig): TestComponent => { + const component = new TestComponent(config); + component.logger = childLogger(loggerTest, 'App'); + return component; +} + const component = new TestComponent(); component.logger = childLogger(loggerTest, 'App'); @@ -628,4 +637,66 @@ describe('Play Transforms', function () { }); }); + + describe('Transform Manager', function() { + + it('Uses user transforms in the order supplied within component', async function() { + const tConfigs: TransformerCommonConfig[] = [ + { + type: 'user', + name: 't1', + defaults: { + title: [ + { + search: "Cool", + replace: "Fun" + }, + { + search: "Track", + replace: "Title" + } + ] + } + }, + { + type: 'user', + name: 't2', + defaults: { + title: [ + { + search: "Cool", + replace: "Bar" + } + ] + } + } + ]; + const tmanager = new TransformerManager(loggerTest, transientCache()); + for(const t of tConfigs) { + tmanager.register(t); + } + + const play = generatePlay({track: 'My Cool Track'}); + + const multiTransformComponent = createTestComponent({transformManager: tmanager}); + multiTransformComponent.config.options = { + playTransform: { + preCompare: [ + { + type: "user", + name: "t2" + }, + { + type: "user", + name: "t1" + } + ] + } + }; + multiTransformComponent.buildTransformRules(); + const transformed = await multiTransformComponent.transformPlay(play, TRANSFORM_HOOK.preCompare); + expect(transformed.data.track).eq('My Bar Title'); + }); + }); + })