Skip to content

feat: Rule component framework with Zod validation and given aliases#47

Open
andmatei wants to merge 16 commits intomainfrom
andmatei/ipa-ui-components
Open

feat: Rule component framework with Zod validation and given aliases#47
andmatei wants to merge 16 commits intomainfrom
andmatei/ipa-ui-components

Conversation

@andmatei
Copy link
Copy Markdown
Collaborator

Summary

  • React component framework for IPA rule enrichment (Rule, RulesSection, Correct, Incorrect, Reason, Examples, Workflow)
  • Zod build-time validation for all Rule component props
  • Given alias config (12 predefined aliases mapping to JSONPaths, following Spectral's pattern)
  • Cross-file validation Docusaurus plugin (unique rule IDs, dependsOn resolution, cycle detection via Kahn's algorithm)

What's in this PR

Component framework

  • Every IPA component in its own folder with co-located CSS module
  • Generic Badge component in src/components/ui/Badge/ with six colour variants
  • IpaMetadata component reads frontmatter state via useDoc() and renders a pill badge above the page title
  • DocItem/Content swizzled in wrap mode to inject IpaMetadata automatically
  • CSS counters for rule numbering, severity-based left border accents, dark mode support

Validation (Zod)

  • ruleIdSchema — validates IPA-{nnnn}-{must|should|may}-{slug} format
  • givenValueSchema — validates known alias or JSONPath starting with $
  • rulePropsSchema — validates all Rule props with cross-field constraints (e.g., informational rules don't need given)
  • Rule component throws during SSR on invalid props, failing the build with actionable errors

Given aliases

  • 12 predefined aliases (delete-operation, schema, spec, etc.) in src/config/givenAliases.ts
  • Shared config used by both Zod validation and future extraction pipeline

Cross-file validation plugin

  • Docusaurus plugin runs during loadContent() — fails the build early
  • Regex-based extraction of <Rule> props from .mdx files
  • Checks: rule ID uniqueness across corpus, dependsOn reference resolution, dependency cycle detection (Kahn's algorithm)

IPA document changes

  • state added to frontmatter of all 36 IPA docs
  • Old :::info[State] admonition blocks removed
  • Redundant slug: lines removed (auto-derived by parseFrontMatter)

Test plan

  • npx vitest run — 44 tests across 3 files (Zod schemas, cross-file validation, frontmatter parsing)
  • npx docusaurus build — full build succeeds with validation plugin active
  • Break a Rule prop in any .mdx file and verify build fails with clear error message

andmatei added 10 commits April 17, 2026 11:49
- Refactor all IPA components into folder-per-component structure
  (Rule/, RulesSection/, Examples/, Workflow/, Correct/, Incorrect/,
  Reason/, IpaMetadata/) each with co-located CSS module
- Extract generic Badge component into src/components/ui/Badge/
  (renamed from Tag — 'badge' is the standard UI pattern name)
- Replace monolithic styles.module.css with per-component CSS modules
- Add IpaMetadata component that reads frontmatter `state` via useDoc()
  and renders a pill tag strip above the page title
- Swizzle DocItem/Content (wrap mode) to inject IpaMetadata automatically
  on every IPA doc page without touching individual files
- Migrate 36 IPA docs: add `state: adopt|experimental` to frontmatter,
  remove old :::info[State] admonition blocks
- Use CSS counters for rule numbering (removes render-time side effects)
- Add severity-based left border accent on Rule cards (must/should/may)
- Unify accordion styles for Examples and Workflow
- Add dark mode support for all severity and state colours
@evergreen-ci-prod
Copy link
Copy Markdown

There is an existing patch(es) for this commit SHA:

Please note that the status that is posted is not in the context of this PR but rather the (latest) existing patch and that may affect some tests that may depend on the particular PR. If your tests do not rely on any PR-specific values (like base or head branch name) then your tests will report the same status. If you would like a patch to run in the context of this PR and abort the other(s), comment 'evergreen retry'.

- Guard Zod validation with SSR check (typeof window === 'undefined')
- Move validation after hook calls to satisfy React Rules of Hooks
- Strip fenced code blocks before regex extraction in validation plugin
- Handle explicit boolean syntax (lintable={true}/lintable={false})
- Restore 0100.mdx as test fixture so validation is exercised end-to-end
- Remove case-insensitive flag from deriveSeverity regex
- Use Zod validation instead of unsafe type casts in IpaMetadata
- Type STATE_TAG_COLOR as Partial<Record<IpaState, BadgeColor>>
- Extract shared Accordion component from duplicated Examples/Workflow
- Extract shared ExampleBlock.module.css from duplicated Correct/Incorrect CSS
- Handle self-closing Rule tags and JSX comments in validation regex
- Throw if Rule rendered outside RulesSection (was silently defaulting)
- Add uniqueness constraint on dependsOn array
- Replace useMemo on deriveSeverity with plain call
- Use explicit color class map in Badge instead of string interpolation
- Remove unused @docusaurus/theme-search-algolia dependency
@maks-m-mongo-leaf
Copy link
Copy Markdown
Collaborator

It would help to review the PR if it were shorter. Is it possible to split it? Would it be reasonable?
Also the linter is complaining for some reason.

@andmatei
Copy link
Copy Markdown
Collaborator Author

It would help to review the PR if it were shorter. Is it possible to split it? Would it be reasonable? Also the linter is complaining for some reason.

@maks-m-mongo-leaf Souds good to me, will make PRs for each component then close this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants