All files / src/pipeline step.js

100% Statements 8/8
100% Branches 0/0
100% Functions 6/6
100% Lines 8/8

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67                        1x         2x         1x 1x                 1x                                   15x 29x                   1x          
/**
 * Pipeline phase interface; subclass name "StepNSuffix" drives index/id/name.
 * @interface
 * @example
 * const step = new Step2Chords();
 * step.index; // 2
 * step.id;    // "step2"
 * step.name;  // "Step 2 (Chords)"
 */
export class Step {
  /** @type {string} Step id "step{index}". */
  get id() {
    return `step${this.index}`;
  }
 
  /** @type {number} Step index from class name. */
  get index() {
    return Number(this.constructor.name.match(/^Step(\d+)/)[1]);
  }
 
  /** @type {string} Display name "Step {index} ({Suffix})". */
  get name() {
    const m = this.constructor.name.match(/^Step(\d+)([A-Z][a-zA-Z]*)$/);
    return `Step ${m[1]} (${m[2]})`;
  }
 
  /**
   * @abstract
   * @return {Object[]} UI parameter descriptors.
   * @throws {Error} When called on a Step subclass that did not override schema().
   */
  schema() {
    throw new Error("Not implemented: schema()");
  }
}
 
/**
 * Trait: adds abstract solve(parameters, solver) to a Step subclass.
 * Non-solvable steps (e.g. pure form definitions) just extend Step directly.
 * @typedef {Step} Solvable
 * @example
 * class Step9Foo extends Solvable(Step) {
 *   schema() { return SCHEMA; }
 *   async solve(parameters, solver) {
 *     const { model } = modelFoo(parameters);
 *     const solution = await solver(model);
 *     return { textOutput: solution ? "ok" : "no solution", solution };
 *   }
 * }
 */
export const Solvable = (Base) =>
  class extends Base {
    /**
     * @abstract
     * Build a model from parameters, hand it to the solver, render a result.
     * @param {Object} parameters - Per-step form values; see the concrete step's schema().
     * @param {function(model: string): Promise<Object>} solver - Pre-bound solver callback.
     * @return {Promise<Object|null>} Per-step result containing the CSP solution (sigma); null reserved for skip cases.
     * @throws {Error} When called on a Solvable subclass that did not override solve().
     */
    solve(parameters, solver) {
      throw new Error(
        `Not implemented: solve(parameters=${typeof parameters}, solver=${typeof solver})`,
      );
    }
  };