slopbrick 0.42.0 → 0.43.0

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.
@@ -6868,6 +6868,26 @@ function dispatchNode(node, parent, path, vctx) {
6868
6868
  // src/engine/parser-rust.ts
6869
6869
  import Parser from "tree-sitter";
6870
6870
  import Rust from "tree-sitter-rust";
6871
+
6872
+ // src/engine/parser-shared.ts
6873
+ function parseTreeSitterSource(parserResult, source) {
6874
+ if (!parserResult.ok) return null;
6875
+ if (!source || source.trim() === "") return null;
6876
+ try {
6877
+ const rawTree = parserResult.parser.parse(source);
6878
+ if (!rawTree) return null;
6879
+ const tree = rawTree;
6880
+ if (!tree || !tree.rootNode) return null;
6881
+ if (tree.rootNode.type === "ERROR" && tree.rootNode.childCount === 0) {
6882
+ return null;
6883
+ }
6884
+ return tree;
6885
+ } catch {
6886
+ return null;
6887
+ }
6888
+ }
6889
+
6890
+ // src/engine/parser-rust.ts
6871
6891
  var cachedParser = null;
6872
6892
  var rustLanguage = null;
6873
6893
  var loadError = null;
@@ -6894,21 +6914,7 @@ function effectiveParser() {
6894
6914
  return getRustParser();
6895
6915
  }
6896
6916
  function parseRust(source) {
6897
- const result = effectiveParser();
6898
- if (!result.ok) return null;
6899
- if (!source || source.trim() === "") return null;
6900
- try {
6901
- const rawTree = result.parser.parse(source);
6902
- if (!rawTree) return null;
6903
- const tree = rawTree;
6904
- if (!tree || !tree.rootNode) return null;
6905
- if (tree.rootNode.type === "ERROR" && tree.rootNode.childCount === 0) {
6906
- return null;
6907
- }
6908
- return tree;
6909
- } catch {
6910
- return null;
6911
- }
6917
+ return parseTreeSitterSource(effectiveParser(), source);
6912
6918
  }
6913
6919
  function isRustParserAvailable() {
6914
6920
  const result = getRustParser();
@@ -7522,8 +7528,6 @@ function mergeTemplateClassNames(filePath, source, facts, templateClassNames) {
7522
7528
  }
7523
7529
  function extractFacts(filePath, ast, source, supportsRsc = true, framework = "react", config) {
7524
7530
  const lineOffsets = buildLineOffsets(source);
7525
- const isTypeScript = /\.tsx?$/i.test(filePath);
7526
- const NON_JSX_FRAMEWORKS = /* @__PURE__ */ new Set(["vue", "svelte", "astro"]);
7527
7531
  const facts = {
7528
7532
  filePath,
7529
7533
  components: [],
@@ -32947,7 +32951,7 @@ var aiCommentRatioRule = createRule({
32947
32951
  message: `Comment-line ratio is ${direction} (${ratio.toFixed(2)} vs corpus mean ${mean3}). Reductive LLMs (GPT-3.5, Claude 3 Haiku) skip comments; expansive LLMs (Claude Haiku 4.5, GPT-OSS) over-comment when prompted for "well-commented code".`,
32948
32952
  line: 1,
32949
32953
  column: 1,
32950
- advice: direction === "low" ? "Add doc comments explaining intent (not just restating the next line) for non-obvious logic." : "Trim comments that just restate the next line. Keep comments that explain WHY, not WHAT."
32954
+ advice: direction === "low" ? "Add doc comments explaining intent (not just restating the next line) for non-obvious logic." : "High comment ratio \u2014 consider whether the comments are intentional (api docs, type defs, tutorials). For functional code, trim comments that just restate the next line. Keep comments that explain WHY, not WHAT."
32951
32955
  }
32952
32956
  ];
32953
32957
  return issues;
@@ -33721,7 +33725,6 @@ function buildTrigramLM(samples, alpha = 1) {
33721
33725
  logProb(context, t) {
33722
33726
  const ctxKey = context.slice(-2).join("|");
33723
33727
  const triKey = `${ctxKey}|${t}`;
33724
- const biKey = context.slice(-1).join("|") + "|" + t;
33725
33728
  const triCount = tri.get(triKey) ?? 0;
33726
33729
  const biCount = bi.get(ctxKey) ?? 0;
33727
33730
  const V = uni.size;
@@ -35514,7 +35517,7 @@ var RESERVED = /* @__PURE__ */ new Set([
35514
35517
  ]);
35515
35518
  var SOURCE_EXTS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
35516
35519
  var SOURCE_ROOTS = ["src", "lib", "app", "components"];
35517
- var CAP = 200;
35520
+ var CAP = 4e3;
35518
35521
  function walk(dir, out, cap) {
35519
35522
  if (!existsSync(dir) || out.length >= cap) return;
35520
35523
  let entries;
@@ -35594,6 +35597,7 @@ var staleFunctionReferenceRule = createRule({
35594
35597
  if (!source) return issues;
35595
35598
  for (const span of extractInlineCodeSpans(source)) {
35596
35599
  const text = span.text;
35600
+ if (span.inBlockComment || span.inComment) continue;
35597
35601
  if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(text)) continue;
35598
35602
  if (text.length < 3) continue;
35599
35603
  if (RESERVED.has(text.toLowerCase())) continue;
@@ -35756,6 +35760,7 @@ var stalePackageReferenceRule = createRule({
35756
35760
  if (!source) return issues;
35757
35761
  const spans = extractInlineCodeSpans(source);
35758
35762
  for (const span of spans) {
35763
+ if (span.inComment) continue;
35759
35764
  const lineStart = source.lastIndexOf("\n", span.index) + 1;
35760
35765
  const lineEnd = source.indexOf("\n", span.index);
35761
35766
  const line = source.slice(lineStart, lineEnd === -1 ? source.length : lineEnd);
@@ -35801,6 +35806,8 @@ var stalePackageReferenceRule = createRule({
35801
35806
  function extractInlineCodeSpans(source) {
35802
35807
  const hits = [];
35803
35808
  const re = /`([^`\n]+?)`/g;
35809
+ const blockRanges = findBlockCommentRanges(source);
35810
+ const commentLines = findCommentLineRanges(source);
35804
35811
  let m;
35805
35812
  while ((m = re.exec(source)) !== null) {
35806
35813
  const text = m[1] ?? "";
@@ -35808,13 +35815,22 @@ function extractInlineCodeSpans(source) {
35808
35815
  const line = upTo.split("\n").length;
35809
35816
  const lastNl = upTo.lastIndexOf("\n");
35810
35817
  const column = lastNl === -1 ? m.index + 1 : m.index - lastNl;
35811
- hits.push({ text, line, column, index: m.index });
35818
+ hits.push({
35819
+ text,
35820
+ line,
35821
+ column,
35822
+ index: m.index,
35823
+ inBlockComment: isInBlockComment(blockRanges, m.index),
35824
+ inComment: commentLines.has(line)
35825
+ });
35812
35826
  }
35813
35827
  return hits;
35814
35828
  }
35815
35829
  function extractMarkdownLinks(source) {
35816
35830
  const hits = [];
35817
35831
  const re = /(?<!\!)\[([^\]]*)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g;
35832
+ const blockRanges = findBlockCommentRanges(source);
35833
+ const commentLines = findCommentLineRanges(source);
35818
35834
  let m;
35819
35835
  while ((m = re.exec(source)) !== null) {
35820
35836
  const target = m[2] ?? "";
@@ -35822,10 +35838,55 @@ function extractMarkdownLinks(source) {
35822
35838
  const line = upTo.split("\n").length;
35823
35839
  const lastNl = upTo.lastIndexOf("\n");
35824
35840
  const column = lastNl === -1 ? m.index + 1 : m.index - lastNl;
35825
- hits.push({ target, line, column });
35841
+ hits.push({
35842
+ target,
35843
+ line,
35844
+ column,
35845
+ index: m.index,
35846
+ inBlockComment: isInBlockComment(blockRanges, m.index),
35847
+ inComment: commentLines.has(line)
35848
+ });
35826
35849
  }
35827
35850
  return hits;
35828
35851
  }
35852
+ function findBlockCommentRanges(source) {
35853
+ const ranges = [];
35854
+ const stack = [];
35855
+ let i = 0;
35856
+ while (i < source.length) {
35857
+ if (source[i] === "/" && source[i + 1] === "/") {
35858
+ const eol = source.indexOf("\n", i);
35859
+ i = eol === -1 ? source.length : eol + 1;
35860
+ continue;
35861
+ }
35862
+ if (source[i] === "/" && source[i + 1] === "*") {
35863
+ stack.push(i);
35864
+ i += 2;
35865
+ continue;
35866
+ }
35867
+ if (source[i] === "*" && source[i + 1] === "/" && stack.length > 0) {
35868
+ const start = stack.pop();
35869
+ ranges.push([start, i + 2]);
35870
+ i += 2;
35871
+ continue;
35872
+ }
35873
+ i += 1;
35874
+ }
35875
+ ranges.sort((a, b) => a[0] - b[0]);
35876
+ return ranges;
35877
+ }
35878
+ function isInBlockComment(ranges, pos) {
35879
+ let lo = 0;
35880
+ let hi = ranges.length - 1;
35881
+ while (lo <= hi) {
35882
+ const mid = lo + hi >>> 1;
35883
+ const [start, end] = ranges[mid];
35884
+ if (pos < start) hi = mid - 1;
35885
+ else if (pos >= end) lo = mid + 1;
35886
+ else return true;
35887
+ }
35888
+ return false;
35889
+ }
35829
35890
  function declaredPackages(cwd) {
35830
35891
  const out = /* @__PURE__ */ new Set();
35831
35892
  const pkgPath = join5(cwd, "package.json");
@@ -35845,8 +35906,63 @@ function declaredPackages(cwd) {
35845
35906
  }
35846
35907
  return out;
35847
35908
  }
35909
+ function findCommentLineRanges(source) {
35910
+ const out = /* @__PURE__ */ new Set();
35911
+ const stack = [];
35912
+ let inLineComment = false;
35913
+ const lines = source.split("\n");
35914
+ for (let i = 0; i < lines.length; i++) {
35915
+ const line = lines[i];
35916
+ const lineNo = i + 1;
35917
+ let j = 0;
35918
+ while (j < line.length) {
35919
+ const c = line[j];
35920
+ const next = line[j + 1];
35921
+ if (!stack.length && c === "/" && next === "/") {
35922
+ inLineComment = true;
35923
+ out.add(lineNo);
35924
+ break;
35925
+ }
35926
+ if (c === "/" && next === "*") {
35927
+ stack.push(lineNo);
35928
+ out.add(lineNo);
35929
+ j += 2;
35930
+ continue;
35931
+ }
35932
+ if (c === "*" && next === "/" && stack.length > 0) {
35933
+ stack.pop();
35934
+ j += 2;
35935
+ continue;
35936
+ }
35937
+ if (c === '"' || c === "'" || c === "`") {
35938
+ const quote = c;
35939
+ j += 1;
35940
+ while (j < line.length) {
35941
+ if (line[j] === "\\") {
35942
+ j += 2;
35943
+ continue;
35944
+ }
35945
+ if (line[j] === quote) {
35946
+ j += 1;
35947
+ break;
35948
+ }
35949
+ j += 1;
35950
+ }
35951
+ continue;
35952
+ }
35953
+ j += 1;
35954
+ }
35955
+ if (stack.length > 0) {
35956
+ out.add(lineNo);
35957
+ }
35958
+ }
35959
+ return out;
35960
+ }
35848
35961
 
35849
35962
  // src/rules/docs/broken-link.ts
35963
+ function looksLikeRegexSyntax(target) {
35964
+ return /\[[^\]]*\]/.test(target) || /^\s*[?:=!]/.test(target) || /\\(?:s|d|w|S|D|W|t|n|r|[^\\])/.test(target) || /[{}|]/.test(target);
35965
+ }
35850
35966
  var brokenLinkRule = createRule({
35851
35967
  id: "docs/broken-link",
35852
35968
  category: "docs",
@@ -35869,6 +35985,8 @@ var brokenLinkRule = createRule({
35869
35985
  if (target.startsWith("#")) continue;
35870
35986
  if (target.startsWith("//")) continue;
35871
35987
  if (target.startsWith("/")) continue;
35988
+ if (link.inBlockComment) continue;
35989
+ if (looksLikeRegexSyntax(target)) continue;
35872
35990
  const filePart = target.split("#")[0] ?? target;
35873
35991
  if (filePart === "") continue;
35874
35992
  const resolved = join6(docDir, filePart);
@@ -37193,8 +37311,16 @@ var DEFAULT_CONFIG3 = {
37193
37311
  // rule definitions are meta-code
37194
37312
  "**/snippet/**",
37195
37313
  // RULE_HINTS examples are intentional bad code
37196
- "**/tests/**"
37314
+ "**/tests/**",
37197
37315
  // all test files (fixtures + unit + integration)
37316
+ // v0.42.0 (post-self-scan cleanup): language visitors are
37317
+ // intentional clones — see the §3 v0.42.0 release notes for
37318
+ // the design rationale. `dup/identical-block` fires 100+
37319
+ // times during self-scan because each visitor shares the
37320
+ // same service-suffix arrays and import-walking preamble.
37321
+ // Suppress these from the self-scan noise floor; they
37322
+ // remain on for user codebases.
37323
+ "**/src/engine/visitors/**"
37198
37324
  ]
37199
37325
  }
37200
37326
  };