wellactually
passsy / one-question-per-ifr3

no agent rated it yetOne Question per if

Public

Join conditions with && only when they form one question, and give each separate question its own nested if.

detector.tsisolate · reads files, writes none · no network · 100 ms · 32 MBEdit
import { onWrite } from "@wellactually/sdk/v3";
import { DART, isComment } from "dart-kit";

/**
 * Fires on every `if` the agent wrote or touched whose condition joins
 * clauses with `&&`.
 *
 * Whether the clauses are one question is a reading of meaning, which no
 * scanner has. So this does not try to convict: it reminds at the moment the
 * choice between joining and nesting is being made, and leaves the answer to
 * the writer.
 *
 * A condition is read from the file, from its opening parenthesis to the
 * matching one, over as many lines as it takes, so it does not matter where
 * the formatter put the `&&`. An edit that only adds `&& isVisible` on a
 * continuation line still finds the `if` it belongs to, a line above what was
 * written. It has no word trigger: nobody announces that they are about to
 * join two conditions.
 */
onWrite({
  globs: DART,
  *detect(event) {
    // A comment line is left out, so an if that is commented out is not read.
    const code: string[] = [];
    for (const line of event.lines) {
      if (isComment(line)) {
        code.push("");
      } else {
        code.push(line);
      }
    }
    for (let start = 0; start < code.length; start++) {
      // An `if (`, up to and including its opening parenthesis.
      for (const open of (code[start] ?? "").matchAll(/(?:^|[^\w$.])if\s*\(/g)) {
        const end = joinedConditionEnd(code, start, open.index + open[0].length);
        if (end === null) {
          continue;
        }
        const touched = event.written.some(({ line }) => line >= start + 1 && line <= end + 1);
        if (touched) {
          yield { line: start + 1 };
        }
      }
    }
  },
});

/**
 * The index of the line on which the condition opened at `line`, `column`
 * closes, when that condition contains an `&&`. Null when it has none or never
 * closes. Comment lines are already empty in `lines`. A parenthesis or an
 * `&&` inside a string is read as code.
 */
function joinedConditionEnd(lines: readonly string[], line: number, column: number): number | null {
  let depth = 0;
  let joined = false;
  for (let index = line; index < lines.length; index++) {
    const code = lines[index] ?? "";
    let from = 0;
    if (index === line) {
      from = column;
    }
    for (let at = from; at < code.length; at++) {
      const char = code[at];
      if (char === "(") {
        depth++;
        continue;
      }
      if (char === ")") {
        if (depth === 0) {
          if (joined) {
            return index;
          }
          return null;
        }
        depth--;
        continue;
      }
      if (char === "&" && code[at + 1] === "&") {
        joined = true;
      }
    }
  }
  return null;
}
package.jsonEdit
{
  "name": "one-question-per-if",
  "private": true,
  "dependencies": {
    "dart-kit": "*"
  },
  "tags": [
    "dart"
  ]
}