@ipation/specbridge 1.0.2 → 1.0.4

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/dist/index.js CHANGED
@@ -1323,9 +1323,7 @@ var ErrorsAnalyzer = class {
1323
1323
  );
1324
1324
  if (errorClasses.length < 2) return null;
1325
1325
  const files = scanner.getFiles();
1326
- let extendsError = 0;
1327
- let extendsCustomBase = 0;
1328
- let customBaseName = null;
1326
+ const baseCount = /* @__PURE__ */ new Map();
1329
1327
  for (const errorClass of errorClasses) {
1330
1328
  const file = files.find((f) => f.path === errorClass.file);
1331
1329
  if (!file) continue;
@@ -1334,22 +1332,27 @@ var ErrorsAnalyzer = class {
1334
1332
  const extendClause = classDecl.getExtends();
1335
1333
  if (extendClause) {
1336
1334
  const baseName = extendClause.getText();
1337
- if (baseName === "Error") {
1338
- extendsError++;
1339
- } else if (baseName.endsWith("Error")) {
1340
- extendsCustomBase++;
1341
- customBaseName = customBaseName || baseName;
1335
+ if (baseName !== "Error" && baseName.endsWith("Error")) {
1336
+ baseCount.set(baseName, (baseCount.get(baseName) || 0) + 1);
1342
1337
  }
1343
1338
  }
1344
1339
  }
1345
- if (extendsCustomBase >= 2 && customBaseName) {
1346
- const confidence = calculateConfidence(extendsCustomBase, errorClasses.length);
1340
+ let customBaseName = null;
1341
+ let maxCount = 0;
1342
+ for (const [baseName, count] of baseCount.entries()) {
1343
+ if (count > maxCount) {
1344
+ maxCount = count;
1345
+ customBaseName = baseName;
1346
+ }
1347
+ }
1348
+ if (maxCount >= 3 && customBaseName) {
1349
+ const confidence = calculateConfidence(maxCount, errorClasses.length);
1347
1350
  return createPattern(this.id, {
1348
1351
  id: "errors-custom-base",
1349
1352
  name: "Custom Error Base Class",
1350
1353
  description: `Custom errors extend a common base class (${customBaseName})`,
1351
1354
  confidence,
1352
- occurrences: extendsCustomBase,
1355
+ occurrences: maxCount,
1353
1356
  examples: errorClasses.slice(0, 3).map((c) => ({
1354
1357
  file: c.file,
1355
1358
  line: c.line,
@@ -1360,7 +1363,7 @@ var ErrorsAnalyzer = class {
1360
1363
  rule: `Custom error classes should extend ${customBaseName}`,
1361
1364
  severity: "medium",
1362
1365
  scope: "src/**/*.ts",
1363
- verifier: "error-hierarchy"
1366
+ verifier: "errors"
1364
1367
  }
1365
1368
  });
1366
1369
  }
@@ -1431,10 +1434,11 @@ var ErrorsAnalyzer = class {
1431
1434
  } else if (text.startsWith("new ") && text.includes("Error")) {
1432
1435
  throwCustom++;
1433
1436
  if (examples.length < 3) {
1437
+ const snippet = text.length > 50 ? text.slice(0, 50) + "..." : text;
1434
1438
  examples.push({
1435
1439
  file: path,
1436
1440
  line: node.getStartLineNumber(),
1437
- snippet: `throw ${text.slice(0, 50)}${text.length > 50 ? "..." : ""}`
1441
+ snippet: `throw ${snippet}`
1438
1442
  });
1439
1443
  }
1440
1444
  }
@@ -1456,7 +1460,7 @@ var ErrorsAnalyzer = class {
1456
1460
  rule: "Throw custom error classes instead of generic Error",
1457
1461
  severity: "medium",
1458
1462
  scope: "src/**/*.ts",
1459
- verifier: "custom-errors-only"
1463
+ verifier: "errors"
1460
1464
  }
1461
1465
  });
1462
1466
  }
@@ -2030,9 +2034,11 @@ var VerificationEngine = class {
2030
2034
  let passed = 0;
2031
2035
  let failed = 0;
2032
2036
  const skipped = 0;
2033
- const timeoutPromise = new Promise(
2034
- (resolve) => setTimeout(() => resolve("timeout"), timeout)
2035
- );
2037
+ let timeoutHandle = null;
2038
+ const timeoutPromise = new Promise((resolve) => {
2039
+ timeoutHandle = setTimeout(() => resolve("timeout"), timeout);
2040
+ timeoutHandle.unref();
2041
+ });
2036
2042
  const verificationPromise = this.verifyFiles(
2037
2043
  filesToVerify,
2038
2044
  decisions,
@@ -2048,17 +2054,25 @@ var VerificationEngine = class {
2048
2054
  }
2049
2055
  }
2050
2056
  );
2051
- const result = await Promise.race([verificationPromise, timeoutPromise]);
2052
- if (result === "timeout") {
2053
- return {
2054
- success: false,
2055
- violations: allViolations,
2056
- checked,
2057
- passed,
2058
- failed,
2059
- skipped: filesToVerify.length - checked,
2060
- duration: timeout
2061
- };
2057
+ let result;
2058
+ try {
2059
+ result = await Promise.race([verificationPromise, timeoutPromise]);
2060
+ if (result === "timeout") {
2061
+ return {
2062
+ success: false,
2063
+ violations: allViolations,
2064
+ checked,
2065
+ passed,
2066
+ failed,
2067
+ skipped: filesToVerify.length - checked,
2068
+ duration: timeout
2069
+ };
2070
+ }
2071
+ } finally {
2072
+ if (timeoutHandle) {
2073
+ clearTimeout(timeoutHandle);
2074
+ timeoutHandle = null;
2075
+ }
2062
2076
  }
2063
2077
  const hasBlockingViolations = allViolations.some((v) => {
2064
2078
  if (level === "commit") {
@@ -2753,7 +2767,7 @@ function formatMarkdownReport(report) {
2753
2767
  lines.push("| Decision | Status | Constraints | Violations | Compliance |");
2754
2768
  lines.push("|----------|--------|-------------|------------|------------|");
2755
2769
  for (const dec of report.byDecision) {
2756
- const complianceEmoji = dec.compliance >= 90 ? "" : dec.compliance >= 70 ? "" : "";
2770
+ const complianceEmoji = dec.compliance >= 90 ? "\u2705" : dec.compliance >= 70 ? "\u26A0\uFE0F" : "\u274C";
2757
2771
  lines.push(
2758
2772
  `| ${dec.title} | ${dec.status} | ${dec.constraints} | ${dec.violations} | ${complianceEmoji} ${dec.compliance}% |`
2759
2773
  );
@@ -2762,15 +2776,15 @@ function formatMarkdownReport(report) {
2762
2776
  }
2763
2777
  lines.push("---");
2764
2778
  lines.push("");
2765
- lines.push("*Generated by [SpecBridge](https://github.com/specbridge/specbridge)*");
2779
+ lines.push("*Generated by [SpecBridge](https://github.com/nouatzi/specbridge)*");
2766
2780
  return lines.join("\n");
2767
2781
  }
2768
2782
  function formatProgressBar(percentage) {
2769
2783
  const width = 20;
2770
2784
  const filled = Math.round(percentage / 100 * width);
2771
2785
  const empty = width - filled;
2772
- const filledChar = "";
2773
- const emptyChar = "";
2786
+ const filledChar = "\u2588";
2787
+ const emptyChar = "\u2591";
2774
2788
  return `\`${filledChar.repeat(filled)}${emptyChar.repeat(empty)}\` ${percentage}%`;
2775
2789
  }
2776
2790
 
@@ -2830,7 +2844,7 @@ function formatContextAsMarkdown(context) {
2830
2844
  lines.push("### Constraints");
2831
2845
  lines.push("");
2832
2846
  for (const constraint of decision.constraints) {
2833
- const typeEmoji = constraint.type === "invariant" ? "" : constraint.type === "convention" ? "" : "";
2847
+ const typeEmoji = constraint.type === "invariant" ? "\u{1F512}" : constraint.type === "convention" ? "\u{1F4CB}" : "\u{1F4A1}";
2834
2848
  const severityBadge = `[${constraint.severity.toUpperCase()}]`;
2835
2849
  lines.push(`- ${typeEmoji} **${severityBadge}** ${constraint.rule}`);
2836
2850
  }