0

I have a class called Conv. (Code at the end) It's for converting Objects via the run Function. In the "real" version there is also a runInverse() for simplicity reasons it's left out in this example.

i.e I can create a Conv and use it like this:

function fn(s: String, inv: Boolean) {
  inv ? "inversed" : s
}

let conv = new Conv();
conv.fromPathToWithFn(data.id, fn, "internal_id");

conv.run({ data: { id: "1234" }}); // => { internal_id: "1234" }

The Converter is essentially a library and now I want to be able to define this fn as part of the conv but without modifying the Class on it's own.

That's so I'm able to access other values from the whole run / runInverse Object so that fn could look like this:

function fn(s: String, inv: Boolean) {
  if (this.payload.otherValue) {
    return "nice"; 
  } else {
    return "s";
  }
}

And a request then would look like:

conv.run({ data: { id: "1234" }, otherValue: "defined" }) // => { internal_id: "nice" });

Here the class

export class Conv {
  converted: Array<any> = []; // The blueprint of conversions to be done
  inverse: Boolean = false; // Whether it's a normal or a inverse conversion (import/export)
  newPayload: object = {}; // the converted vehicle

  constructor() { }

  /**
   * Copies a value from one path into another
   *
   * @function fromPathTo
   * @memberof Conv
   *
   * @param {String} from Source-Path
   * @param {String} to Destination-Path
   * @return {void}
   */
  fromPathTo(from: String, to: String) {
    this.converted.push({ from, to });
  }

  /**
   * Takes the value in the Source-Path and uses it as an argument on the Converter-Function before putting it
   * into the Destination-Path
   *
   * @function fromPathToWithFn
   * @memberof Conv
   *
   * @param {String} from Source-Path
   * @param {Function} fn Converter-Function
   * @param {String} to Destination-Path
   */
  fromPathToWithFn(from: String, fn: Function, to: String) {
    this.converted.push({ from, fn, to });
  }

  /**
   *
   * @param {Object} payload The vehicle to be converted
   * @returns {Object} newPayload The converted vehicle
   */
  run(payload: Object, parentString: String = "") {
    this.inverse = false;

    /**
     * Without this if-Statement we can't use default values
     */
    if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
      return payload;
    }

    for (let prop in payload) {
      let currentPath: string = prop;
      if (parentString !== "") {
        currentPath = parentString + "." + prop;
      }
      if (
        typeof payload[prop] === "object" && !Array.isArray(payload[prop])
      ) {
        this.run(payload[prop], currentPath);
      } else {
        /**
         * @param {string} newProp Destination-Path
         */
        let newProp: string = this.converted.find(
          (_) => _.from === currentPath
        )?.to;
        /**
         * @param {Function|undefined} func Converter-Function
        */
        let func: Function | undefined = this.converted.find(
          (_) => _.from === currentPath
        )?.fn;
        /**
         * @param {string|null} def Default-Value
        */
        let def: String | null = this.converted.find(
          (_) => _.from === currentPath
        )?.def;

        // Check wether Value should even be used in this conversion
        if (newProp === undefined || newProp === null) {
          break;
        }

        if (newProp && newProp !== prop) {
          // Only call the function if it's not undefined
          // and set the Destination-Path to the default value if the Source-Value is null
          typeof func !== "undefined"
            ? lodash.set(
              this.newPayload,
              newProp,
              func(this.run(lodash.get(payload, prop)), this.inverse)
            )
            : this.run(lodash.get(payload, prop)) === null ||
              typeof this.run(lodash.get(payload, prop)) === "undefined"
              ? lodash.set(this.newPayload, newProp, def)
              : lodash.set(
                this.newPayload,
                newProp,
                this.run(lodash.get(payload, prop))
              );
        } else {
          // Only call the function if it's not undefined
          // and set the Destination-Path to the default value if the Source-Value is null
          typeof func !== "undefined"
            ? lodash.set(
              this.newPayload,
              prop,
              func(this.run(lodash.get(payload, prop)), this.inverse)
            )
            : this.run(lodash.get(this.newPayload, currentPath)) === null ||
              typeof this.run(lodash.get(this.newPayload, prop)) === "undefined"
              ? lodash.set(this.newPayload, currentPath, def)
              : lodash.set(
                this.newPayload,
                currentPath,
                this.run(lodash.get(payload, prop))
              );
        }
      }
    }
    return this.newPayload;
  }
}

9
  • 1
    Please edit to provide a minimal reproducible example we can paste into our own IDEs and get to work on it. A verbal description of a class isn't something an IDE can use, so we either have to give answers without testing it first, or make guesses about what your class looks like, and it's easy to guess incorrectly. Commented Jul 17, 2023 at 14:41
  • I added the class code to my original question Commented Jul 17, 2023 at 15:17
  • 1
    By the by, there is no JSON involved here. Those are just objects, not "JSON-Objects". Using terms like "JSON-Objects" dilutes the meaning of JSON, which is simply a format for exchanging data. Commented Jul 17, 2023 at 15:26
  • 1
    @JaredSmith I'm not sure why "object" doesn't work. If you want to talk about objects with adornments, talk about the adornments. Seems like we made it this far without needing a special word for objects. If we must, POJO works, although I don't know if Java people might have a problem talking about POJO-to-POJO transformation :). Commented Jul 17, 2023 at 16:13
  • 1
    @JaredSmith "plain object" (the very term you used) works fine (although there is no precise definition). Same for POJO though, which commonly have getters and accessors. Commented Jul 17, 2023 at 19:45

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.