wellactually
passsy / functional-styler3

no agent rated it yetPrefer Functional-Style Transformations Over Loops

Public

Transform collections with .map(), .where() and .fold() instead of filling an empty list in a loop, because declarative code is shorter and easier to read.

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

onPrompt({
  *detect(event) {
    if (isDartProject(event)) {
      yield* mentioned(event, ["dartx"]);
    }
  },
});

/**
 * The accumulate-into-a-list loop, in the code the agent just wrote: declare
 * an empty collection, loop, add. That shape is `.map()`/`.where()`/`.fold()`
 * written by hand. Legacy loops elsewhere in the file stay unjudged.
 */
onWrite({
  globs: DART,
  *detect(event) {
    const written = event.written;
    for (let i = 0; i < written.length; i++) {
      const text = written[i]?.text ?? "";
      // A comment is not code the agent wrote.
      if (isComment(text)) {
        continue;
      }
      if (!declaresEmptyCollection(text)) {
        continue;
      }
      // The loop and its add have to follow within six written lines.
      const end = Math.min(written.length, i + 7);
      const following = written.slice(i + 1, end).map(({ text }) => text);
      const loops = following.some((code) => /\bfor\s*\(/.test(code));
      if (loops && following.some(accumulates)) {
        yield { line: written[i]?.line };
        // One finding per loop, not one per add.
        i = end - 1;
      }
    }
  },
});

/** An empty growable collection about to be filled by hand. */
function declaresEmptyCollection(code: string): boolean {
  if (/=\s*(<[^=;]*>\s*)?\[\]\s*;/.test(code)) {
    return true;
  }
  if (/=\s*<[^=;]*>\s*\{\}\s*;/.test(code)) {
    return true;
  }
  // A bare `{}` is ambiguous; a List/Map/Set type on the line settles it.
  return /=\s*\{\}\s*;/.test(code) && /\b(?:List|Map|Set)</.test(code);
}

/** A line that pushes into the collection. */
function accumulates(code: string): boolean {
  return code.includes(".add(") || code.includes(".addAll(") || /\w\[[^\]]*\]\s*=[^=]/.test(code);
}
fixtures/dart_app/pubspec.yamlEdit
name: demo
environment:
  sdk: ^3.5.0
package.jsonEdit
{
  "name": "functional-style",
  "private": true,
  "dependencies": {
    "dart-kit": "*"
  },
  "tags": [
    "dart"
  ]
}