@modyo/widget-validator
v0.1.4
Published
Validator for Modyo widgets built with Dynamic UI
Readme
@modyo/widget-validator
Validator for Modyo widgets built with Dynamic UI. Ships both as a CLI and as a programmatic library.
Installation
npm install --save-dev @modyo/widget-validatorOr run it without installing:
npx @modyo/widget-validator ./path/to/widgetCLI usage
modyo-widget-validator ./path/to/widgetExit code is 0 when no errors are reported, 1 otherwise. Warnings do not affect the exit code.
Sample output:
╔══════════════════════════════════════╗
║ Modyo Widget Validator ║
║ v0.1.0 ║
╚══════════════════════════════════════╝
🔍 Validating widget at: /path/to/widget
═══════════════════════════════════════
VALIDATION REPORT
═══════════════════════════════════════
Widget: /path/to/widget
Score: 100%
Passed: 110/110
✅ PASSED - Widget meets all requirements
✅ All checks passed!Programmatic usage
import { validateWidgetPath } from "@modyo/widget-validator";
const report = await validateWidgetPath("./path/to/widget");
if (!report.passing) {
for (const issue of report.errors) {
console.error(`[${issue.category}] ${issue.message}`);
if (issue.file) console.error(` → ${issue.file}`);
if (issue.suggestion) console.error(` 💡 ${issue.suggestion}`);
}
}validateWidgetPath(projectPath, options?)
Validates a widget at the given filesystem path. Returns a Promise<ValidationReport>.
validateWidget(files, options?)
Validates a widget represented as an array of VirtualFile. Useful when the widget exists in memory rather than on disk. See "Known limitations" below.
ValidateOptions
interface ValidateOptions {
/** Categories to skip (e.g. ["Accessibility"]). */
excludeCategories?: string[];
}Score is recalculated after exclusion, so skipped categories don't bias the result.
ValidationReport
interface ValidationReport {
widgetPath: string;
score: number; // 0–100
passing: boolean; // true iff errors.length === 0
totalChecks: number;
passed: number;
errors: Issue[];
warnings: Issue[];
timestamp: string; // ISO 8601
version: string; // version of @modyo/widget-validator that produced the report
}
interface Issue {
severity: "error" | "warning";
category: string;
rule: string;
message: string;
file?: string; // path relative to widget root, when applicable
line?: number;
suggestion?: string;
}Rules
The validator runs 20 rules organized by category. A rule may produce multiple checks (e.g. "Required Files" checks ~17 files individually).
| Category | What it checks |
|---|---|
| Folder Structure | The widget has the expected directory layout (src/, src/components/, etc.) |
| Required Files | Files like package.json, vite.config.ts, src/main.tsx exist |
| Legacy Files | No files from the previous stack (CRA, legacy configs) remain |
| Naming Conventions | Repositories are PascalCaseRepository.ts, components are PascalCase.tsx, hooks are useX.ts |
| Dependencies | Required dependencies are present, forbidden ones absent, peer deps meet minimum versions |
| TypeScript | tsconfig.json has strict: true, JSX configured, target ≥ ES2020 |
| Vite Config | vite.config.ts includes React plugin and Vitest config |
| TanStack Query | QueryProvider is set up correctly |
| Zustand Store | useUIStore exists and doesn't hold server-fetched data |
| i18n | src/locales/en.json and src/locales/es.json exist and are non-empty |
| Testing | A tests/ folder, setup file, and at least one test exist; hooks have tests; tests follow folder conventions |
| Error Handling | src/utils/errorHandler.ts exists and exports the expected helpers |
| Repository Pattern | At least one repository file with async methods exists |
| Portal System | DContextProvider is set up in src/main.tsx; modals/offcanvas register in availablePortals |
| UI Patterns | No container-fluid className is used (use container) |
| Project Structure | Only README.md lives at the project root (no scattered .md files) |
| Data States | TSX files using query hooks check isLoading/isPending, isError, and empty states |
| Error Boundary | An ErrorBoundary component exists and is used in src/App.tsx |
| Accessibility | <DInput> has labels, <DButton> (icon-only) has text/aria-label, <img> has alt |
Known limitations
validateWidget and empty directories (v0.1)
VirtualFile[] cannot represent empty directories. The validator requires several directories to exist (src/hooks, src/types, etc.), and feeding it a VirtualFile[] constructed from a real widget will lose those empty directories during the round-trip, causing false "Missing required folder" errors.
Workaround: include a sentinel file in each empty directory (e.g. <dir>/.gitkeep).
This restriction will be lifted in v0.2 via an in-memory filesystem abstraction.
License
See LICENSE.md for the Modyo license.
