Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@
## 2024-05-24 - Pre-compile RegExp in nested loops
**Learning:** Instantiating `new RegExp()` inside nested array methods like `.filter` and `.some` creates a severe O(N*M) performance bottleneck, especially when matching two large lists (e.g., documented tests vs. actual test files).
**Action:** Always pre-compile regular expressions and derived strings into an array of "matcher" objects outside of the loop before iterating, which shifts the instantiation cost from O(N*M) to O(N).

## 2024-06-25 - [O(N*M) Basename Overhead]
**Learning:** In nested loops like array `.filter` and `.some`, repeatedly calling string manipulation functions like `basename(path)` inside the loop creates an O(N*M) bottleneck, executing the string parsing M times per item.
**Action:** Always precompute property lookups and string manipulations like `basename` into an array of mapped objects outside the loop before executing the cross-comparison, shifting the cost to strictly O(N).
27 changes: 18 additions & 9 deletions cli/commands/diff.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -348,8 +348,8 @@ function diffTests(dir, config = {}) {
// Glob-aware matching (documented entries are often patterns or basenames).
const codeArr = [...codeTests];

// PERFORMANCE OPTIMIZATION: Pre-compile regular expressions to avoid O(N*M)
// instantiation bottlenecks inside the nested .filter and .some loops below.
// PERFORMANCE OPTIMIZATION: Pre-compile regular expressions and replace O(N*M)
// nested `.filter` and `.some` loops with a single-pass Set-based cross-comparison.
const docMatchers = [...docTests].map(docEntry => {
const entry = String(docEntry).trim();
const hasSlash = entry.includes('/');
Expand All @@ -363,17 +363,26 @@ function diffTests(dir, config = {}) {
};
});

const matches = (matcher, codeRel) => {
const subject = matcher.hasSlash ? codeRel : basename(codeRel);
return matcher.rx.test(subject);
};
const codeObjs = codeArr.map(c => ({ rel: c, base: basename(c) }));
const matchedDocs = new Set();
const matchedCode = new Set();

for (const m of docMatchers) {
for (const c of codeObjs) {
const subject = m.hasSlash ? c.rel : c.base;
if (m.rx.test(subject)) {
matchedDocs.add(m);
matchedCode.add(c);
}
}
}

return {
title: 'Test Files',
icon: 'πŸ§ͺ',
onlyInDocs: docMatchers.filter(m => !codeArr.some(c => matches(m, c))).map(m => m.original),
onlyInCode: codeArr.filter(c => !docMatchers.some(m => matches(m, c))),
matched: docMatchers.filter(m => codeArr.some(c => matches(m, c))).map(m => m.original),
onlyInDocs: docMatchers.filter(m => !matchedDocs.has(m)).map(m => m.original),
onlyInCode: codeObjs.filter(c => !matchedCode.has(c)).map(c => c.rel),
matched: [...matchedDocs].map(m => m.original),
};
}

Expand Down
25 changes: 17 additions & 8 deletions cli/validators/docs-diff.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ function diffTests(dir, config) {
// Exact-string comparison produced the false "N documented but not found".
const codeArr = [...codeTests];

// PERFORMANCE OPTIMIZATION: Pre-compile regular expressions to avoid O(N*M)
// instantiation bottlenecks inside the nested .filter and .some loops below.
// PERFORMANCE OPTIMIZATION: Pre-compile regular expressions and replace O(N*M)
// nested `.filter` and `.some` loops with a single-pass Set-based cross-comparison.
const docMatchers = [...docTests].map(docEntry => {
const entry = String(docEntry).trim();
const hasSlash = entry.includes('/');
Expand All @@ -188,15 +188,24 @@ function diffTests(dir, config) {
};
});

const matches = (matcher, codeRel) => {
const subject = matcher.hasSlash ? codeRel : basename(codeRel);
return matcher.rx.test(subject);
};
const codeObjs = codeArr.map(c => ({ rel: c, base: basename(c) }));
const matchedDocs = new Set();
const matchedCode = new Set();

for (const m of docMatchers) {
for (const c of codeObjs) {
const subject = m.hasSlash ? c.rel : c.base;
if (m.rx.test(subject)) {
matchedDocs.add(m);
matchedCode.add(c);
}
}
}

return {
title: 'Test Files',
onlyInDocs: docMatchers.filter(m => !codeArr.some(c => matches(m, c))).map(m => m.original),
onlyInCode: codeArr.filter(c => !docMatchers.some(m => matches(m, c))),
onlyInDocs: docMatchers.filter(m => !matchedDocs.has(m)).map(m => m.original),
onlyInCode: codeObjs.filter(c => !matchedCode.has(c)).map(c => c.rel),
};
}

Expand Down