Skip to content
Merged
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
26 changes: 14 additions & 12 deletions docs/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,30 +92,31 @@ Override score, severity, or enable/disable individual rules:

### All Rule IDs

<!-- RULE_TABLE_START — auto-generated by scripts/sync-rule-docs.ts, do not edit manually -->
**Structure (9 rules)**

| Rule ID | Default Score | Default Severity |
|---------|--------------|-----------------|
| `no-auto-layout` | -7 | blocking |
| `absolute-position-in-auto-layout` | -10 | blocking |
| `missing-responsive-behavior` | -4 | risk |
| `no-auto-layout` | -10 | blocking |
| `absolute-position-in-auto-layout` | -7 | blocking |
| `fixed-size-in-auto-layout` | -3 | risk |
| `missing-size-constraint` | -3 | risk |
| `missing-responsive-behavior` | -3 | risk |
| `group-usage` | -5 | risk |
| `fixed-size-in-auto-layout` | -5 | risk |
| `missing-size-constraint` | -5 | risk |
| `unnecessary-node` | -2 | suggestion |
| `z-index-dependent-layout` | -5 | risk |
| `deep-nesting` | -4 | risk |
| `z-index-dependent-layout` | -5 | risk |
| `unnecessary-node` | -2 | suggestion |

**Token (7 rules)**

| Rule ID | Default Score | Default Severity |
|---------|--------------|-----------------|
| `raw-color` | -2 | missing-info |
| `raw-font` | -8 | blocking |
| `raw-font` | -4 | risk |
| `inconsistent-spacing` | -2 | missing-info |
| `magic-number-spacing` | -3 | missing-info |
| `raw-shadow` | -7 | risk |
| `raw-opacity` | -5 | risk |
| `magic-number-spacing` | -3 | risk |
| `raw-shadow` | -3 | missing-info |
| `raw-opacity` | -2 | missing-info |
| `multiple-fill-colors` | -3 | missing-info |

**Component (4 rules)**
Expand All @@ -134,7 +135,7 @@ Override score, severity, or enable/disable individual rules:
| `default-name` | -2 | missing-info |
| `non-semantic-name` | -2 | missing-info |
| `inconsistent-naming-convention` | -2 | missing-info |
| `numeric-suffix-name` | -2 | missing-info |
| `numeric-suffix-name` | -1 | suggestion |
| `too-long-name` | -1 | suggestion |

**Behavior (4 rules)**
Expand All @@ -145,6 +146,7 @@ Override score, severity, or enable/disable individual rules:
| `prototype-link-in-design` | -2 | missing-info |
| `overflow-behavior-unknown` | -3 | missing-info |
| `wrap-behavior-unknown` | -3 | missing-info |
<!-- RULE_TABLE_END -->

### Example Configs

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"test:run": "vitest run",
"lint": "tsc --noEmit",
"build:plugin": "bash scripts/build-plugin.sh",
"sync-docs": "tsx scripts/sync-rule-docs.ts",
"clean": "rm -rf dist"
},
"files": [
Expand Down Expand Up @@ -69,6 +70,7 @@
"@types/pngjs": "^6.0.5",
"playwright": "^1.58.2",
"tsup": "^8.5.1",
"tsx": "^4.19.0",
"typescript": "^5.9.3",
"vitest": "^4.1.0"
}
Expand Down
51 changes: 40 additions & 11 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

85 changes: 85 additions & 0 deletions scripts/sync-rule-docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* Auto-generate rule tables in docs/REFERENCE.md from rule-config.ts + rule registry.
*
* Usage: npx tsx scripts/sync-rule-docs.ts
*
* Replaces content between RULE_TABLE_START and RULE_TABLE_END markers in REFERENCE.md.
*/

// Import rules to populate registry
import "../src/core/rules/index.js";
import { ruleRegistry } from "../src/core/rules/rule-registry.js";
import { RULE_CONFIGS } from "../src/core/rules/rule-config.js";
import { CATEGORIES } from "../src/core/contracts/category.js";
import type { Category } from "../src/core/contracts/category.js";
import type { RuleId } from "../src/core/contracts/rule.js";
import { readFileSync, writeFileSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = dirname(fileURLToPath(import.meta.url));
const REFERENCE_PATH = resolve(__dirname, "../docs/REFERENCE.md");
const START_MARKER = "<!-- RULE_TABLE_START";
const END_MARKER = "<!-- RULE_TABLE_END -->";

function generateTables(): string {
const lines: string[] = [];

for (const category of CATEGORIES) {
const rules = ruleRegistry
.getByCategory(category as Category)
.map((r) => {
const id = r.definition.id as RuleId;
const config = RULE_CONFIGS[id];
if (!config) {
throw new Error(`Missing RULE_CONFIGS entry for rule "${id}"`);
}
return { id, config };
});

const label = category.charAt(0).toUpperCase() + category.slice(1);
lines.push(`**${label} (${rules.length} rules)**`);
lines.push("");
lines.push("| Rule ID | Default Score | Default Severity |");
lines.push("|---------|--------------|-----------------|");

for (const { id, config } of rules) {
lines.push(`| \`${id}\` | ${config.score} | ${config.severity} |`);
}

lines.push("");
}

// Remove trailing empty line
if (lines.at(-1) === "") lines.pop();

return lines.join("\n");
}

const content = readFileSync(REFERENCE_PATH, "utf-8");
const startIdx = content.indexOf(START_MARKER);
const endIdx = content.indexOf(END_MARKER);

if (startIdx === -1 || endIdx === -1) {
console.error("RULE_TABLE markers not found in REFERENCE.md");
process.exit(1);
}
Comment on lines +63 to +66
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fail fast when markers are misordered.

The current guard misses the endIdx <= startIdx case, which can corrupt the rewritten section.

Suggested fix
-if (startIdx === -1 || endIdx === -1) {
+if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) {
   console.error("RULE_TABLE markers not found in REFERENCE.md");
   process.exit(1);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (startIdx === -1 || endIdx === -1) {
console.error("RULE_TABLE markers not found in REFERENCE.md");
process.exit(1);
}
if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) {
console.error("RULE_TABLE markers not found in REFERENCE.md");
process.exit(1);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/sync-rule-docs.ts` around lines 63 - 66, The guard that checks for
RULE_TABLE markers only tests for startIdx === -1 or endIdx === -1 but misses
the case where endIdx <= startIdx; update the check in the sync-rule-docs.ts
logic (where startIdx and endIdx are computed) to also treat endIdx <= startIdx
as an error, logging a clear message like "RULE_TABLE markers misordered" (or
similar) and exiting (process.exit(1)) to fail fast and avoid corrupting the
rewritten section.


const before = content.slice(0, startIdx);
const after = content.slice(endIdx + END_MARKER.length);
const tables = generateTables();

const updated =
before +
`${START_MARKER} — auto-generated by scripts/sync-rule-docs.ts, do not edit manually -->\n` +
tables +
"\n" +
END_MARKER +
after;

if (content === updated) {
console.log("docs/REFERENCE.md is already up to date.");
} else {
writeFileSync(REFERENCE_PATH, updated, "utf-8");
console.log("docs/REFERENCE.md updated.");
}
10 changes: 5 additions & 5 deletions src/core/contracts/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export interface Rule {
* Rule ID type for type safety
*/
export type RuleId =
// Structure (9)
// Structure
| "no-auto-layout"
| "absolute-position-in-auto-layout"
| "fixed-size-in-auto-layout"
Expand All @@ -100,26 +100,26 @@ export type RuleId =
| "deep-nesting"
| "z-index-dependent-layout"
| "unnecessary-node"
// Token (7)
// Token
| "raw-color"
| "raw-font"
| "inconsistent-spacing"
| "magic-number-spacing"
| "raw-shadow"
| "raw-opacity"
| "multiple-fill-colors"
// Component (4)
// Component
| "missing-component"
| "detached-instance"
| "missing-component-description"
| "variant-structure-mismatch"
// Naming (5)
// Naming
| "default-name"
| "non-semantic-name"
| "inconsistent-naming-convention"
| "numeric-suffix-name"
| "too-long-name"
// Behavior (4)
// Behavior
| "text-truncation-unhandled"
| "prototype-link-in-design"
| "overflow-behavior-unknown"
Expand Down
2 changes: 1 addition & 1 deletion src/core/engine/scoring.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ describe("calculateGrade (via calculateScores)", () => {
const categories: Category[] = ["structure", "token", "component", "naming", "behavior"];
const rulesPerCat: Record<Category, string[]> = {
structure: ["no-auto-layout", "group-usage", "deep-nesting", "fixed-size-in-auto-layout", "missing-responsive-behavior", "absolute-position-in-auto-layout", "missing-size-constraint", "z-index-dependent-layout", "unnecessary-node"],
token: ["raw-color", "raw-font", "inconsistent-spacing", "magic-number-spacing", "raw-shadow"],
token: ["raw-color", "raw-font", "inconsistent-spacing", "magic-number-spacing", "raw-shadow", "raw-opacity", "multiple-fill-colors"],
component: ["missing-component", "detached-instance", "missing-component-description", "variant-structure-mismatch"],
naming: ["default-name", "non-semantic-name", "inconsistent-naming-convention", "numeric-suffix-name", "too-long-name"],
behavior: ["text-truncation-unhandled", "prototype-link-in-design", "overflow-behavior-unknown", "wrap-behavior-unknown"],
Expand Down
10 changes: 1 addition & 9 deletions src/core/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,9 @@
export * from "./rule-registry.js";
export * from "./rule-config.js";

// Structure rules (9)
// Rule definitions (auto-register via defineRule on import)
export * from "./structure/index.js";

// Token rules (7)
export * from "./token/index.js";

// Component rules (4)
export * from "./component/index.js";

// Naming rules (5)
export * from "./naming/index.js";

// Behavior rules (4)
export * from "./behavior/index.js";
Loading
Loading