@jwilger/pi-development-system 0.10.4 → 0.10.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jwilger/pi-development-system",
3
- "version": "0.10.4",
3
+ "version": "0.10.5",
4
4
  "description": "A pi extension package representing a seasoned approach to software development using a full AI SDLC.",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -26,7 +26,7 @@ const KINDS: readonly Kind[] = [
26
26
  inline: (line, after) =>
27
27
  lastGroup(/reason\s*=\s*"([^"]*)"/, line) ??
28
28
  lastGroup(/\)\]\s*\/\/\s*(.+)$/, after) ??
29
- lastGroup(/\)\]\s*\/\*\s*(.+?)\s*\*\/\s*$/, after),
29
+ lastGroup(/\)\]\s*\/\*\s*([^*]+?)\*\/\s*$/, after),
30
30
  },
31
31
  {
32
32
  marker: "#![allow(",
@@ -13,7 +13,7 @@ export type RedFirstGuardDeps = { pi: ExtensionAPI; state: SessionState };
13
13
  const GATE_ID = "tdd.red-first";
14
14
 
15
15
  /** Test code written inside a source file (Rust `#[cfg(test)]`/`#[test]`): that edit is the RED step itself. */
16
- const INLINE_TEST = /#\[(?:cfg\(test\)|test|tokio::test|rstest)\]/g;
16
+ const INLINE_TEST = /#\[(?:cfg\(test\)|test|test_case|rstest|proptest|\w+::test)\b/g;
17
17
 
18
18
  const countInlineTests = (text: string): number => text.match(INLINE_TEST)?.length ?? 0;
19
19
 
@@ -25,14 +25,29 @@ const existing = (cwd: string, path: string): string => {
25
25
  }
26
26
  };
27
27
 
28
- /** Does this edit add test code? A whole-file write counts only markers beyond those already on disk. */
29
- const addsInlineTest = (
30
- input: { content: string } | { edits: ReadonlyArray<{ newText: string }> },
31
- before: () => string,
32
- ): boolean =>
33
- "content" in input
34
- ? countInlineTests(input.content) > countInlineTests(before())
35
- : countInlineTests(input.edits.map((e) => e.newText).join("\n")) > 0;
28
+ type EditInput =
29
+ | { content: string }
30
+ | { edits: ReadonlyArray<{ oldText: string; newText: string }> };
31
+
32
+ /** Is every edit inside the file's existing `#[cfg(test)]` module? Changing a test's expectation is RED itself. */
33
+ const insideTestModule = (edits: ReadonlyArray<{ oldText: string }>, file: string): boolean => {
34
+ const start = file.indexOf("#[cfg(test)]");
35
+ return start >= 0 && edits.every((e) => e.oldText !== "" && file.indexOf(e.oldText) > start);
36
+ };
37
+
38
+ /**
39
+ * Does this edit write or change test code? A write counts markers beyond those on disk, an edit
40
+ * counts markers beyond those it replaces (an anchor line is not a new test), or must sit wholly
41
+ * inside the existing test module.
42
+ */
43
+ const touchesInlineTest = (input: EditInput, before: () => string): boolean => {
44
+ if ("content" in input) return countInlineTests(input.content) > countInlineTests(before());
45
+ const added = input.edits.reduce(
46
+ (n, e) => n + Math.max(0, countInlineTests(e.newText) - countInlineTests(e.oldText)),
47
+ 0,
48
+ );
49
+ return added > 0 || insideTestModule(input.edits, before());
50
+ };
36
51
 
37
52
  /** Exemption classes a machine cannot see; the departure names which one applies (research 02). */
38
53
  const JUDGED_EXEMPTIONS =
@@ -58,7 +73,7 @@ export function registerRedFirstGuard(deps: RedFirstGuardDeps): void {
58
73
  if (lastTestRun !== undefined && lastTestRun.exitCode !== 0) return undefined;
59
74
  const path = normalizeRepoPath(ctx.cwd, event.input.path, homedir());
60
75
  if (classifyPath(path) !== "source") return undefined;
61
- if (addsInlineTest(event.input, () => existing(ctx.cwd, path))) return undefined;
76
+ if (touchesInlineTest(event.input, () => existing(ctx.cwd, path))) return undefined;
62
77
  if (departure.hasOpen()) {
63
78
  departure.consume();
64
79
  return undefined;