@birdapi/velinstyle 0.7.0 → 0.9.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.
- package/README.de.md +135 -224
- package/README.md +134 -223
- package/cli/blueprint.js +8 -0
- package/cli/blueprints/bottom-nav-mobile.html +17 -0
- package/cli/blueprints/cookie-consent.html +9 -0
- package/cli/blueprints/empty-state.html +5 -0
- package/cli/blueprints/filter-bar.html +15 -0
- package/cli/blueprints/notification-center.html +13 -0
- package/cli/blueprints/onboarding.html +23 -0
- package/cli/blueprints/pricing-table.html +20 -0
- package/cli/blueprints/settings-panel.html +20 -0
- package/cli/cli-manifest.json +97 -0
- package/cli/docgen/extract-a11y.js +89 -0
- package/cli/docgen/extract-attributes.js +95 -0
- package/cli/docgen/extract-cli.js +50 -0
- package/cli/docgen/extract-components.js +175 -0
- package/cli/docgen/extract-meta.js +32 -0
- package/cli/docgen/extract-rules.js +76 -0
- package/cli/docgen/extract-tokens.js +79 -0
- package/cli/docgen/extract-utilities.js +75 -0
- package/cli/docgen/markdown.js +43 -0
- package/cli/docs-generate.js +196 -0
- package/cli/index.js +236 -5
- package/cli/layout-audit.js +325 -0
- package/cli/meta.js +97 -0
- package/cli/perf-audit.js +174 -0
- package/cli/pii-scanner.js +134 -0
- package/cli/scaffold-recipes.json +70 -0
- package/cli/scaffold.js +155 -0
- package/cli/scanner-rules-data.js +62 -0
- package/cli/scanner.js +136 -1
- package/cli/search-index.js +163 -0
- package/cli/tokens-build.js +21 -1
- package/cli/tokens-validate.js +69 -0
- package/components/a11y-entry.js +42 -0
- package/components/a11y-utils.js +71 -0
- package/components/focus-manager.js +45 -8
- package/components/index.js +40 -11
- package/components/runtime/component-loaders.js +43 -0
- package/components/runtime/index.js +77 -0
- package/components/runtime-entry.js +10 -0
- package/components/sanitize.js +135 -28
- package/components/shadow-a11y-styles.js +18 -0
- package/components/velin-accordion.js +12 -0
- package/components/velin-announcer.js +35 -0
- package/components/velin-bottom-nav.js +108 -0
- package/components/velin-carousel.js +2 -2
- package/components/velin-code-block.js +142 -0
- package/components/velin-combobox.js +149 -0
- package/components/velin-command.js +142 -0
- package/components/velin-copy.js +18 -5
- package/components/velin-counter.js +155 -0
- package/components/velin-dialog.js +9 -1
- package/components/velin-email.js +94 -0
- package/components/velin-flip.js +220 -0
- package/components/velin-icon.js +99 -22
- package/components/velin-lightbox.js +8 -3
- package/components/velin-live-dot.js +90 -0
- package/components/velin-menubar.js +83 -0
- package/components/velin-modal.js +6 -3
- package/components/velin-popover.js +34 -2
- package/components/velin-rating.js +91 -0
- package/components/velin-reveal.js +22 -0
- package/components/velin-scroll-top.js +1 -1
- package/components/velin-search.js +267 -0
- package/components/velin-secure-field.js +99 -0
- package/components/velin-segmented-control.js +108 -0
- package/components/velin-sheet.js +107 -0
- package/components/velin-sparkline.js +227 -0
- package/components/{velin-stepper-wc.js → velin-stepper.js} +37 -8
- package/components/velin-theme-toggle.js +284 -60
- package/components/velin-toast.js +4 -0
- package/components/{velin-tooltip-wc.js → velin-tooltip.js} +22 -3
- package/core/a11y/component-contracts.json +221 -0
- package/core/attributes/index.js +6 -0
- package/core/attributes/registry.js +268 -0
- package/core/highlight/highlight.js +114 -0
- package/core/highlight/index.js +29 -0
- package/core/highlight/languages/_utils.js +52 -0
- package/core/highlight/languages/blade.js +16 -0
- package/core/highlight/languages/css.js +26 -0
- package/core/highlight/languages/html.js +17 -0
- package/core/highlight/languages/js.js +58 -0
- package/core/highlight/languages/json.js +14 -0
- package/core/highlight/languages/markdown.js +16 -0
- package/core/highlight/languages/php.js +39 -0
- package/core/highlight/languages/plain.js +7 -0
- package/core/highlight/languages/shell.js +33 -0
- package/core/highlight/languages/sql.js +20 -0
- package/core/highlight/languages/typescript.js +28 -0
- package/core/highlight/observe.js +53 -0
- package/core/highlight/registry.js +107 -0
- package/core/highlight/render.js +35 -0
- package/core/highlight/types.js +28 -0
- package/core/meta/build.js +293 -0
- package/core/meta/index.js +17 -0
- package/core/meta/schema.js +49 -0
- package/core/motion/effects.js +54 -0
- package/core/motion/index.js +76 -0
- package/core/motion/scheduler.js +72 -0
- package/core/motion/scroll.js +32 -0
- package/core/motion/stagger.js +24 -0
- package/core/search/docs-url.js +96 -0
- package/core/search/engine.js +139 -0
- package/core/search/highlight.js +48 -0
- package/core/search/index.js +126 -0
- package/core/search/providers.js +36 -0
- package/core/search/types.js +61 -0
- package/core/search/worker-client.js +56 -0
- package/core/search/worker.js +20 -0
- package/dist/chunks/a11y-utils-IRC7LOPF.js +16 -0
- package/dist/chunks/attributes-3BZLI7XF.js +364 -0
- package/dist/chunks/attributes-4N5JP4CG.js +364 -0
- package/dist/chunks/attributes-5Q2WXGRC.js +374 -0
- package/dist/chunks/attributes-AIR7SVLK.js +364 -0
- package/dist/chunks/attributes-BGRN5XZO.js +364 -0
- package/dist/chunks/attributes-BVSQAYLR.js +364 -0
- package/dist/chunks/attributes-CDYFUY7Y.js +364 -0
- package/dist/chunks/attributes-JMYJZBPE.js +364 -0
- package/dist/chunks/attributes-R5JY3X4O.js +374 -0
- package/dist/chunks/attributes-STYCS3O5.js +391 -0
- package/dist/chunks/attributes-TNSPQTHX.js +374 -0
- package/dist/chunks/attributes-TPANLMLF.js +391 -0
- package/dist/chunks/blade-LIQLVKZQ.js +19 -0
- package/dist/chunks/browser-MRKYZPEH.js +1149 -0
- package/dist/chunks/chunk-2354NEBP.js +109 -0
- package/dist/chunks/chunk-2VNA7G7S.js +109 -0
- package/dist/chunks/chunk-42VVPW6N.js +132 -0
- package/dist/chunks/chunk-7FFAMRFV.js +44 -0
- package/dist/chunks/chunk-7MCGPHVC.js +69 -0
- package/dist/chunks/chunk-AQLRJSGG.js +109 -0
- package/dist/chunks/chunk-EWPSDMQT.js +109 -0
- package/dist/chunks/chunk-F7OLHTGX.js +22 -0
- package/dist/chunks/chunk-J472ERN2.js +242 -0
- package/dist/chunks/chunk-LA7264K4.js +85 -0
- package/dist/chunks/chunk-M5CHQVP6.js +61 -0
- package/dist/chunks/chunk-MKZP2TBH.js +89 -0
- package/dist/chunks/chunk-QTJJ3DPO.js +109 -0
- package/dist/chunks/chunk-RDE3QE7Z.js +89 -0
- package/dist/chunks/chunk-RSMRR27R.js +109 -0
- package/dist/chunks/chunk-RZQVWFHW.js +109 -0
- package/dist/chunks/chunk-SRL6EWHP.js +109 -0
- package/dist/chunks/chunk-U4XHMZ7D.js +109 -0
- package/dist/chunks/chunk-V5YIUA6G.js +109 -0
- package/dist/chunks/chunk-XIET2VSZ.js +109 -0
- package/dist/chunks/chunk-XYLJ2GCB.js +205 -0
- package/dist/chunks/chunk-Z4JYQ2XX.js +51 -0
- package/dist/chunks/chunk-ZPSPKUYD.js +109 -0
- package/dist/chunks/css-MQ5YU77P.js +28 -0
- package/dist/chunks/highlight-GJHHV4KM.js +37 -0
- package/dist/chunks/highlight-XTHRKBA3.js +37 -0
- package/dist/chunks/html-ZODC4DLQ.js +20 -0
- package/dist/chunks/js-MNSNYTJU.js +7 -0
- package/dist/chunks/json-VEM2HFH3.js +17 -0
- package/dist/chunks/markdown-E7OPGS3S.js +19 -0
- package/dist/chunks/php-MLL7T3LT.js +41 -0
- package/dist/chunks/plain-LJJDC5TN.js +8 -0
- package/dist/chunks/runtime-entry.js +14 -0
- package/dist/chunks/shell-QTRK4U4E.js +35 -0
- package/dist/chunks/sql-PPWLHGJ2.js +23 -0
- package/dist/chunks/typescript-JT3CCYWL.js +30 -0
- package/dist/chunks/velin-accordion-FBIPAEXG.js +105 -0
- package/dist/chunks/velin-accordion-QAQO7BI7.js +117 -0
- package/dist/chunks/velin-announcer-PVTXXCWR.js +33 -0
- package/dist/chunks/velin-bottom-nav-2N2TYWOF.js +86 -0
- package/dist/chunks/velin-bottom-nav-7GEMPIM6.js +86 -0
- package/dist/chunks/velin-bottom-nav-CTU6FFZV.js +101 -0
- package/dist/chunks/velin-bottom-nav-N3DFQR66.js +86 -0
- package/dist/chunks/velin-carousel-Y5VCOABZ.js +213 -0
- package/dist/chunks/velin-carousel-ZTBANFQQ.js +213 -0
- package/dist/chunks/velin-code-block-ASUBTAQV.js +119 -0
- package/dist/chunks/velin-code-block-CIAURDRJ.js +132 -0
- package/dist/chunks/velin-code-block-TSUKPY4C.js +123 -0
- package/dist/chunks/velin-code-block-Y6CM726Q.js +119 -0
- package/dist/chunks/velin-collapse-5XYBUIID.js +80 -0
- package/dist/chunks/velin-combobox-2KDTCQ7N.js +155 -0
- package/dist/chunks/velin-combobox-NXS4QB4R.js +155 -0
- package/dist/chunks/velin-combobox-UGA56HP3.js +155 -0
- package/dist/chunks/velin-command-CKDNO4BW.js +148 -0
- package/dist/chunks/velin-command-M7RNHUPR.js +136 -0
- package/dist/chunks/velin-command-ONKO2A3J.js +136 -0
- package/dist/chunks/velin-command-TMLSRGIU.js +136 -0
- package/dist/chunks/velin-copy-G2TZ5YBB.js +81 -0
- package/dist/chunks/velin-copy-NYDBOKXT.js +81 -0
- package/dist/chunks/velin-copy-T5KDTDXP.js +81 -0
- package/dist/chunks/velin-countdown-4ZVDGK4R.js +101 -0
- package/dist/chunks/velin-countdown-5XSTN3BH.js +101 -0
- package/dist/chunks/velin-countdown-7AIY66CU.js +101 -0
- package/dist/chunks/velin-counter-ISCTEAHI.js +118 -0
- package/dist/chunks/velin-counter-L5FYJF7A.js +121 -0
- package/dist/chunks/velin-dialog-D2GUHSCD.js +144 -0
- package/dist/chunks/velin-dialog-ELFOZIXZ.js +152 -0
- package/dist/chunks/velin-dialog-GTTZI564.js +147 -0
- package/dist/chunks/velin-dialog-IJLFDXAJ.js +144 -0
- package/dist/chunks/velin-dialog-TNS3WXMB.js +144 -0
- package/dist/chunks/velin-drawer-BE6TYN3H.js +130 -0
- package/dist/chunks/velin-drawer-DLL2GLT6.js +130 -0
- package/dist/chunks/velin-drawer-MJS6WCF7.js +130 -0
- package/dist/chunks/velin-dropdown-PLUIFA5M.js +172 -0
- package/dist/chunks/velin-email-N5B5ZYTE.js +90 -0
- package/dist/chunks/velin-email-NTM6DG3V.js +90 -0
- package/dist/chunks/velin-email-RBX6ZR4S.js +90 -0
- package/dist/chunks/velin-haptic-4QQTM3RK.js +50 -0
- package/dist/chunks/velin-icon-7M76DOPB.js +164 -0
- package/dist/chunks/velin-icon-KZO3IEHG.js +164 -0
- package/dist/chunks/velin-icon-WTFPG2DD.js +191 -0
- package/dist/chunks/velin-icon-ZTSKUOVN.js +193 -0
- package/dist/chunks/velin-lightbox-6E7CAATP.js +149 -0
- package/dist/chunks/velin-lightbox-I75U6JF4.js +140 -0
- package/dist/chunks/velin-lightbox-QOTB4PRL.js +140 -0
- package/dist/chunks/velin-lightbox-UCD6N7HF.js +140 -0
- package/dist/chunks/velin-live-dot-RJHX2DGY.js +74 -0
- package/dist/chunks/velin-live-dot-XHUZCIDZ.js +67 -0
- package/dist/chunks/velin-menubar-I426AED2.js +86 -0
- package/dist/chunks/velin-menubar-J66JXRWW.js +86 -0
- package/dist/chunks/velin-menubar-SFEXJE56.js +86 -0
- package/dist/chunks/velin-modal-2HOBXE6F.js +176 -0
- package/dist/chunks/velin-modal-5HYNNNUI.js +176 -0
- package/dist/chunks/velin-modal-AEOTZ67O.js +177 -0
- package/dist/chunks/velin-modal-GLI2XZZB.js +176 -0
- package/dist/chunks/velin-persist-DFPL3QP4.js +110 -0
- package/dist/chunks/velin-popover-EXINRIGJ.js +145 -0
- package/dist/chunks/velin-popover-HQW6Q2Y6.js +172 -0
- package/dist/chunks/velin-popover-OXX7MRZ6.js +145 -0
- package/dist/chunks/velin-popover-T72HK3DF.js +151 -0
- package/dist/chunks/velin-popover-YKCCROJG.js +145 -0
- package/dist/chunks/velin-progress-ring-E4YRLZHH.js +66 -0
- package/dist/chunks/velin-rating-6CDBI6DG.js +91 -0
- package/dist/chunks/velin-rating-N4DI2XNL.js +91 -0
- package/dist/chunks/velin-rating-XRQJV4LO.js +91 -0
- package/dist/chunks/velin-scroll-top-F2FCZNYD.js +58 -0
- package/dist/chunks/velin-scroll-top-OHYVVHHY.js +58 -0
- package/dist/chunks/velin-scrollspy-OKCT4FDV.js +50 -0
- package/dist/chunks/velin-search-2XRQFBCS.js +556 -0
- package/dist/chunks/velin-search-4YHJWYSS.js +556 -0
- package/dist/chunks/velin-search-7B4KJ6TX.js +557 -0
- package/dist/chunks/velin-search-LWHY23Q5.js +474 -0
- package/dist/chunks/velin-secure-field-6PV7RZDJ.js +95 -0
- package/dist/chunks/velin-secure-field-H7FSBUJW.js +95 -0
- package/dist/chunks/velin-secure-field-OFNAXCDP.js +95 -0
- package/dist/chunks/velin-segmented-control-EKL4E3BL.js +109 -0
- package/dist/chunks/velin-segmented-control-GYD5BIXQ.js +109 -0
- package/dist/chunks/velin-segmented-control-PQX6LKOJ.js +109 -0
- package/dist/chunks/velin-sheet-3OGI4HD7.js +119 -0
- package/dist/chunks/velin-sheet-OUK6572T.js +119 -0
- package/dist/chunks/velin-sheet-R2Y67X6H.js +119 -0
- package/dist/chunks/velin-sparkline-GVEANJVW.js +184 -0
- package/dist/chunks/velin-sparkline-KDA3GQAN.js +162 -0
- package/dist/chunks/velin-sparkline-XVTFC6GE.js +181 -0
- package/dist/chunks/velin-stepper-2ZIHLKGM.js +141 -0
- package/dist/chunks/velin-stepper-7ECRUYHD.js +148 -0
- package/dist/chunks/velin-stepper-FYEUEWE6.js +141 -0
- package/dist/chunks/velin-stepper-X54WGHDG.js +141 -0
- package/dist/chunks/velin-stepper-wc-QU3KRVQR.js +133 -0
- package/dist/chunks/velin-tabs-5UQ5ZVMV.js +138 -0
- package/dist/chunks/velin-theme-toggle-32J2CBNC.js +291 -0
- package/dist/chunks/velin-theme-toggle-BNNS7WLV.js +285 -0
- package/dist/chunks/velin-theme-toggle-NO7V4TWI.js +285 -0
- package/dist/chunks/velin-theme-toggle-QELCJM2Q.js +291 -0
- package/dist/chunks/velin-toast-OMMOA2DK.js +109 -0
- package/dist/chunks/velin-toast-RCZ4CSUC.js +109 -0
- package/dist/chunks/velin-toast-RSF2IHT3.js +113 -0
- package/dist/chunks/velin-toast-WEUBTJG6.js +109 -0
- package/dist/chunks/velin-tooltip-664IOHZA.js +112 -0
- package/dist/chunks/velin-tooltip-BDHGRTQB.js +112 -0
- package/dist/chunks/velin-tooltip-HVUOKNVX.js +112 -0
- package/dist/chunks/velin-tooltip-wc-LXDVT6DE.js +103 -0
- package/dist/chunks/worker-client-R6DBYPFT.js +46 -0
- package/dist/llms.test.txt +40 -0
- package/dist/llms.txt +40 -0
- package/dist/search-index.json +1773 -0
- package/dist/search-index.test.json +1773 -0
- package/dist/themes/brutalist.min.css +1 -1
- package/dist/themes/midnight.min.css +1 -1
- package/dist/themes/pastel.min.css +1 -1
- package/dist/themes/retro.min.css +1 -1
- package/dist/themes/sunset.min.css +1 -1
- package/dist/velin-agent.json +684 -0
- package/dist/velin-agent.test.json +684 -0
- package/dist/velinstyle-components.iife.js +7959 -2199
- package/dist/velinstyle-components.js +7982 -2174
- package/dist/velinstyle-components.min.js +521 -90
- package/dist/velinstyle.css +1290 -282
- package/dist/velinstyle.d.ts +54 -0
- package/dist/velinstyle.min.css +1 -1
- package/examples/search-index.schema.json +33 -0
- package/package.json +57 -10
- package/src/a11y/authentication.css +37 -0
- package/src/a11y/consistent-help.css +22 -0
- package/src/a11y/dragging-alternatives.css +30 -0
- package/src/a11y/focus-appearance.css +20 -0
- package/src/a11y/high-contrast-aaa.css +16 -26
- package/src/a11y/security.css +18 -0
- package/src/a11y/skip-link.css +3 -1
- package/src/a11y/sr-only.css +1 -1
- package/src/base/reset.css +0 -25
- package/src/base/wc-placeholder.css +102 -0
- package/src/components/attributes.css +42 -0
- package/src/components/highlight.css +182 -0
- package/src/components/input-group.css +1 -2
- package/src/components/nav.css +151 -151
- package/src/components/search.css +95 -0
- package/src/components/stepper.css +2 -4
- package/src/components/timeline.css +1 -2
- package/src/components/tooltip.css +2 -4
- package/src/layout/container.css +5 -5
- package/src/layout/grid.css +8 -8
- package/src/layout/patterns.css +5 -5
- package/src/themes/brutalist.css +2 -11
- package/src/themes/corporate.css +0 -9
- package/src/themes/earth.css +0 -9
- package/src/themes/forest.css +0 -9
- package/src/themes/midnight.css +1 -10
- package/src/themes/neon.css +0 -9
- package/src/themes/nordic.css +0 -9
- package/src/themes/ocean.css +0 -9
- package/src/themes/pastel.css +1 -10
- package/src/themes/retro.css +2 -11
- package/src/themes/sharp.css +0 -7
- package/src/themes/soft.css +0 -7
- package/src/themes/sunset.css +1 -10
- package/src/tokens/color.css +45 -46
- package/src/tokens/fonts.css +10 -0
- package/src/tokens/motion.css +7 -0
- package/src/tokens/typography.css +4 -5
- package/src/utilities/animation.css +99 -3
- package/src/utilities/chart-animation.css +101 -0
- package/src/utilities/display.css +3 -3
- package/src/utilities/divide.css +2 -6
- package/src/utilities/filter-effects.css +103 -0
- package/src/utilities/responsive.css +4 -4
- package/src/utilities/safe-area.css +39 -0
- package/src/utilities/scroll-animation.css +34 -0
- package/src/utilities/spacing.css +17 -8
- package/src/utilities/text.css +4 -1
- package/src/velinstyle.css +12 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.9.0",
|
|
3
|
+
"commands": [
|
|
4
|
+
{
|
|
5
|
+
"name": "init",
|
|
6
|
+
"summary": "Create velinstyle.config.js",
|
|
7
|
+
"flags": [],
|
|
8
|
+
"example": "velinstyle init"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "build",
|
|
12
|
+
"summary": "Build custom CSS with selected layers from config",
|
|
13
|
+
"flags": [],
|
|
14
|
+
"example": "velinstyle build"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "themes",
|
|
18
|
+
"summary": "List available built-in themes",
|
|
19
|
+
"flags": [],
|
|
20
|
+
"example": "velinstyle themes"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "add",
|
|
24
|
+
"summary": "Add a single component CSS file to your project",
|
|
25
|
+
"flags": [],
|
|
26
|
+
"example": "velinstyle add button"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "icons",
|
|
30
|
+
"summary": "Manage icon providers (list, add, remove, build)",
|
|
31
|
+
"flags": ["--icons", "--variant"],
|
|
32
|
+
"subcommands": ["list", "add", "remove", "build"],
|
|
33
|
+
"example": "velinstyle icons add lucide --icons menu,search"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "scan",
|
|
37
|
+
"summary": "Security, accessibility, CSS, and PII scanner",
|
|
38
|
+
"flags": ["--format", "--severity", "--only", "--fix", "--fix-dry-run", "--fix-lang"],
|
|
39
|
+
"example": "velinstyle scan . --only pii --fix-dry-run"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "prefix",
|
|
43
|
+
"summary": "Add missing velin- prefix to classes (dry-run; use --write)",
|
|
44
|
+
"flags": ["--write", "--map", "--bootstrap-display"],
|
|
45
|
+
"example": "velinstyle prefix src/ --write"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "blueprint",
|
|
49
|
+
"summary": "Print HTML blueprint snippets",
|
|
50
|
+
"flags": ["--output", "-o"],
|
|
51
|
+
"subcommands": ["list"],
|
|
52
|
+
"example": "velinstyle blueprint modal -o snippet.html"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "scaffold",
|
|
56
|
+
"summary": "Generate layout HTML from natural language prompt",
|
|
57
|
+
"flags": ["--output", "-o", "--json"],
|
|
58
|
+
"subcommands": ["list-intents"],
|
|
59
|
+
"example": "velinstyle scaffold \"dashboard with sidebar\""
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "layout",
|
|
63
|
+
"summary": "Responsive layout audit (flex, grid, viewport)",
|
|
64
|
+
"flags": ["--json", "--write", "--dry-run"],
|
|
65
|
+
"subcommands": ["audit", "suggest", "fix"],
|
|
66
|
+
"example": "velinstyle layout suggest index.html"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "perf",
|
|
70
|
+
"summary": "Performance audit for images and scripts",
|
|
71
|
+
"flags": ["--json", "--write", "--dry-run"],
|
|
72
|
+
"subcommands": ["audit", "suggest", "fix"],
|
|
73
|
+
"example": "velinstyle perf audit samples/"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"name": "tokens",
|
|
77
|
+
"summary": "Build or validate design tokens JSON",
|
|
78
|
+
"flags": ["--input", "--output", "-o"],
|
|
79
|
+
"subcommands": ["build", "validate"],
|
|
80
|
+
"example": "velinstyle tokens validate --input examples/tokens.full.json"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "docs",
|
|
84
|
+
"summary": "Generate developer reference Markdown",
|
|
85
|
+
"flags": ["--scope", "--out"],
|
|
86
|
+
"subcommands": ["generate"],
|
|
87
|
+
"example": "velinstyle docs generate --scope all"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"name": "meta",
|
|
91
|
+
"summary": "Build Velin-Meta agent bundle (velin-agent.json, llms.txt)",
|
|
92
|
+
"flags": ["--out", "--llms-out", "--base-url", "--no-llms"],
|
|
93
|
+
"subcommands": ["page"],
|
|
94
|
+
"example": "velinstyle meta"
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'fs';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { banner, heading, table } from './markdown.js';
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const PKG_ROOT = join(__dirname, '..', '..');
|
|
8
|
+
|
|
9
|
+
/** @type {{ id: string, level: string, name: string, owner: string, status: string, testId: string }[]} */
|
|
10
|
+
export const WCAG_AAA_CRITERIA = [
|
|
11
|
+
{ id: '1.3.1', level: 'A', name: 'Info and Relationships', owner: 'Author + CSS', status: 'partial', testId: 'scan-a11y' },
|
|
12
|
+
{ id: '1.4.3', level: 'AA', name: 'Contrast (Minimum)', owner: 'Tokens', status: 'pass', testId: 'test:contrast' },
|
|
13
|
+
{ id: '1.4.6', level: 'AAA', name: 'Contrast (Enhanced)', owner: 'Tokens', status: 'pass', testId: 'test:contrast' },
|
|
14
|
+
{ id: '1.4.11', level: 'AA', name: 'Non-text Contrast', owner: 'Tokens + WC', status: 'partial', testId: 'test:a11y' },
|
|
15
|
+
{ id: '2.1.1', level: 'A', name: 'Keyboard', owner: 'Web Components', status: 'partial', testId: 'test:a11y' },
|
|
16
|
+
{ id: '2.3.3', level: 'AAA', name: 'Animation from Interactions', owner: 'CSS + Motion', status: 'pass', testId: 'reduced-motion' },
|
|
17
|
+
{ id: '2.4.1', level: 'A', name: 'Bypass Blocks', owner: 'CSS skip-link', status: 'pass', testId: 'scan-a11y' },
|
|
18
|
+
{ id: '2.4.7', level: 'AA', name: 'Focus Visible', owner: 'CSS focus', status: 'pass', testId: 'test:a11y' },
|
|
19
|
+
{ id: '2.4.11', level: 'AA', name: 'Focus Not Obscured (Minimum)', owner: 'CSS', status: 'pass', testId: 'focus-not-obscured' },
|
|
20
|
+
{ id: '2.4.13', level: 'AAA', name: 'Focus Appearance', owner: 'CSS', status: 'pass', testId: 'focus-appearance' },
|
|
21
|
+
{ id: '2.5.7', level: 'AA', name: 'Dragging Movements', owner: 'CSS + Sample', status: 'pass', testId: 'wcag22-dragging' },
|
|
22
|
+
{ id: '2.5.8', level: 'AA', name: 'Target Size', owner: 'CSS + WC', status: 'pass', testId: 'target-size' },
|
|
23
|
+
{ id: '3.2.6', level: 'A', name: 'Consistent Help', owner: 'CSS', status: 'pass', testId: 'consistent-help' },
|
|
24
|
+
{ id: '3.3.2', level: 'A', name: 'Labels or Instructions', owner: 'Forms + WC', status: 'partial', testId: 'scan-a11y' },
|
|
25
|
+
{ id: '3.3.7', level: 'A', name: 'Redundant Entry', owner: 'velin-persist + Author', status: 'partial', testId: 'velin-persist' },
|
|
26
|
+
{ id: '3.3.8', level: 'AA', name: 'Accessible Authentication', owner: 'CSS + Sample', status: 'pass', testId: 'wcag22-auth' },
|
|
27
|
+
{ id: '4.1.2', level: 'A', name: 'Name, Role, Value', owner: 'Web Components', status: 'partial', testId: 'contracts' },
|
|
28
|
+
{ id: '4.1.3', level: 'AA', name: 'Status Messages', owner: 'Announcer + WC', status: 'pass', testId: 'live-regions' },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
export function loadComponentContracts(pkgRoot = PKG_ROOT) {
|
|
32
|
+
const path = join(pkgRoot, 'core', 'a11y', 'component-contracts.json');
|
|
33
|
+
if (!existsSync(path)) return { wcagLevel: 'AAA', components: {} };
|
|
34
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function renderWcagAaaMatrix(contracts) {
|
|
38
|
+
let md = banner('core/a11y + src/a11y');
|
|
39
|
+
md += heading(1, 'WCAG 2.2 AAA framework matrix');
|
|
40
|
+
md += '\n> **Using VelinStyle does not certify your application.** This matrix tracks what the **framework** provides by default.\n\n';
|
|
41
|
+
md += `Framework target: **WCAG 2.2 Level ${contracts.wcagLevel || 'AAA'}** (token defaults + component contracts).\n\n`;
|
|
42
|
+
|
|
43
|
+
md += heading(2, 'Success criteria');
|
|
44
|
+
md += table(
|
|
45
|
+
['Criterion', 'Level', 'Name', 'Owner', 'Status', 'Test'],
|
|
46
|
+
WCAG_AAA_CRITERIA.map((c) => [
|
|
47
|
+
c.id,
|
|
48
|
+
c.level,
|
|
49
|
+
c.name,
|
|
50
|
+
c.owner,
|
|
51
|
+
c.status,
|
|
52
|
+
`\`${c.testId}\``,
|
|
53
|
+
]),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const comps = contracts.components || {};
|
|
57
|
+
const rows = Object.entries(comps).sort(([a], [b]) => a.localeCompare(b));
|
|
58
|
+
md += heading(2, 'Web component contracts');
|
|
59
|
+
md += table(
|
|
60
|
+
['Element', 'Status', 'Keyboard', 'Live region', 'Required attrs'],
|
|
61
|
+
rows.map(([tag, c]) => [
|
|
62
|
+
`\`<${tag}>\``,
|
|
63
|
+
c.status || '—',
|
|
64
|
+
c.keyboard || '—',
|
|
65
|
+
c.liveRegion || '—',
|
|
66
|
+
(c.requiredAttributes || []).map((a) => `\`${a}\``).join(', ') || '—',
|
|
67
|
+
]),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
md += '\nRun `npm run test:a11y:coverage` for coverage score.\n';
|
|
71
|
+
return md;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function renderComponentA11ySection(tag, contracts) {
|
|
75
|
+
const c = contracts.components?.[tag];
|
|
76
|
+
if (!c) return '';
|
|
77
|
+
let md = heading(2, 'Accessibility');
|
|
78
|
+
md += `WCAG contract status: **${c.status}** (framework target: ${contracts.wcagLevel}).\n\n`;
|
|
79
|
+
if (c.roles?.length) md += `- **Roles:** ${c.roles.map((r) => `\`${r}\``).join(', ')}\n`;
|
|
80
|
+
if (c.keyboard) md += `- **Keyboard:** ${c.keyboard}\n`;
|
|
81
|
+
if (c.liveRegion) md += `- **Live region:** \`${c.liveRegion}\`\n`;
|
|
82
|
+
if (c.reducedMotion) md += `- **Reduced motion:** honored\n`;
|
|
83
|
+
if (c.requiredAttributes?.length) {
|
|
84
|
+
md += `- **Required attributes:** ${c.requiredAttributes.map((a) => `\`${a}\``).join(', ')}\n`;
|
|
85
|
+
}
|
|
86
|
+
if (c.notes) md += `- **Notes:** ${c.notes}\n`;
|
|
87
|
+
md += '\n';
|
|
88
|
+
return md;
|
|
89
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
import { listRegisteredAttributes } from '../../core/attributes/registry.js';
|
|
3
|
+
import { banner, heading } from './markdown.js';
|
|
4
|
+
|
|
5
|
+
const ATTRIBUTE_DOCS = {
|
|
6
|
+
'velin-modal': 'Opens a modal dialog (bridges to `<velin-modal>`).',
|
|
7
|
+
'velin-tabs': 'Tab navigation (bridges to `<velin-tabs>`).',
|
|
8
|
+
'velin-accordion': 'Accordion sections (bridges to `<velin-accordion>`).',
|
|
9
|
+
'velin-tooltip': 'Tooltip on hover/focus (bridges to `<velin-tooltip>`).',
|
|
10
|
+
'velin-copy': 'Copy text to clipboard (bridges to `<velin-copy>`).',
|
|
11
|
+
'velin-counter': 'Animated number counter (bridges to `<velin-counter>`).',
|
|
12
|
+
'velin-notify': 'Show a toast notification (bridges to `<velin-toast>`).',
|
|
13
|
+
'velin-theme': 'Theme toggle or set `data-velin-theme`.',
|
|
14
|
+
'velin-progress': 'Progress bar or ring (`ring` for `<velin-progress-ring>`).',
|
|
15
|
+
'velin-search': 'Attach VelinSearch to an element.',
|
|
16
|
+
'velin-reveal': 'Reveal element when scrolled into view.',
|
|
17
|
+
'velin-fade': 'Fade-in on scroll.',
|
|
18
|
+
'velin-slide': 'Slide-in on scroll (`up`, `down`, …).',
|
|
19
|
+
'velin-scale': 'Scale-in on scroll.',
|
|
20
|
+
'velin-parallax': 'Parallax background (`slow` optional).',
|
|
21
|
+
'velin-hover': 'Hover lift/glow animation.',
|
|
22
|
+
'velin-stagger': 'Stagger child animations (delay in ms).',
|
|
23
|
+
'velin-scroll': 'Smooth scroll to anchor (`href="#id"`).',
|
|
24
|
+
'velin-anchor': 'Scroll-margin for anchor targets.',
|
|
25
|
+
'velin-lazy': 'Lazy-load images with optional skeleton.',
|
|
26
|
+
'velin-skeleton': 'Skeleton placeholder (`text`, `avatar`, `image`, …).',
|
|
27
|
+
'velin-loading': 'Loading spinner state.',
|
|
28
|
+
'velin-grid': 'Auto grid layout (column count).',
|
|
29
|
+
'velin-code': 'Code block with copy button and VelinHighlight syntax colors (use `language` or `velin-code="js"`).',
|
|
30
|
+
'velin-quote': 'Styled blockquote.',
|
|
31
|
+
'velin-highlight': 'Inline text mark (not syntax highlighting — use `velin-code` or `velinSyntax`).',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const A11Y_NOTES = {
|
|
35
|
+
'velin-reveal': 'Honors `prefers-reduced-motion`: content shown immediately without animation.',
|
|
36
|
+
'velin-fade': 'Honors `prefers-reduced-motion`.',
|
|
37
|
+
'velin-slide': 'Honors `prefers-reduced-motion`.',
|
|
38
|
+
'velin-scale': 'Honors `prefers-reduced-motion`.',
|
|
39
|
+
'velin-parallax': 'Disabled under `prefers-reduced-motion` (CSS + motion runtime).',
|
|
40
|
+
'velin-hover': 'Motion reduced globally when user prefers reduced motion.',
|
|
41
|
+
'velin-stagger': 'Stagger delays collapse under reduced motion.',
|
|
42
|
+
'velin-scroll': 'Uses `scroll-behavior: auto` when reduced motion is preferred.',
|
|
43
|
+
'velin-skeleton': 'Sets `aria-hidden` only on empty placeholders — do not use on containers with real text.',
|
|
44
|
+
'velin-loading': 'Sets `aria-busy`, `role="status"`, default `aria-label="Loading"`.',
|
|
45
|
+
'velin-notify': 'Dispatches toast event; pair with `<velin-announcer>` or `initA11y()`.',
|
|
46
|
+
'velin-lazy': 'Adds `loading="lazy"` on `<img>` only.',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export function extractAttributes() {
|
|
50
|
+
return listRegisteredAttributes().map((name) => ({
|
|
51
|
+
name,
|
|
52
|
+
description: ATTRIBUTE_DOCS[name] || 'Velin HTML attribute extension.',
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function renderAttribute(attr) {
|
|
57
|
+
let md = banner('velinstyle docs generate');
|
|
58
|
+
md += heading(1, attr.name);
|
|
59
|
+
md += `\n${attr.description}\n\n`;
|
|
60
|
+
md += '## Example\n\n```html\n';
|
|
61
|
+
if (attr.name === 'velin-code') {
|
|
62
|
+
md += '<pre velin-code="js" language="js"><code>const x = 42;</code></pre>\n';
|
|
63
|
+
} else if (attr.name === 'velin-scroll') {
|
|
64
|
+
md += '<a href="#section" velin-scroll>Jump to section</a>\n';
|
|
65
|
+
} else {
|
|
66
|
+
md += `<div ${attr.name}${attr.name === 'velin-slide' ? '="up"' : ''}>…</div>\n`;
|
|
67
|
+
}
|
|
68
|
+
md += '```\n';
|
|
69
|
+
if (A11Y_NOTES[attr.name]) {
|
|
70
|
+
md += '\n## Accessibility\n\n';
|
|
71
|
+
md += `${A11Y_NOTES[attr.name]}\n`;
|
|
72
|
+
}
|
|
73
|
+
return md;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function renderAttributesIndex(attrs) {
|
|
77
|
+
let md = banner('velinstyle docs generate');
|
|
78
|
+
md += heading(1, 'Velin HTML attributes');
|
|
79
|
+
md += '\nDeclarative extensions interpreted by `bootAttributes()` / `bootFromDOM({ attributes: true })`.\n\n';
|
|
80
|
+
md += '| Attribute | Description |\n| --- | --- |\n';
|
|
81
|
+
for (const a of attrs) {
|
|
82
|
+
md += `| [\`${a.name}\`](./${a.name}.md) | ${a.description} |\n`;
|
|
83
|
+
}
|
|
84
|
+
return md;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function writeAttributesDocs(outDir) {
|
|
88
|
+
const attrs = extractAttributes();
|
|
89
|
+
const written = [];
|
|
90
|
+
for (const a of attrs) {
|
|
91
|
+
written.push({ path: join(outDir, 'attributes', `${a.name}.md`), content: renderAttribute(a) });
|
|
92
|
+
}
|
|
93
|
+
written.push({ path: join(outDir, 'attributes', 'README.md'), content: renderAttributesIndex(attrs) });
|
|
94
|
+
return written;
|
|
95
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
|
+
import { banner, heading, table } from './markdown.js';
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
|
|
8
|
+
/** Commands registered in cli/index.js switch */
|
|
9
|
+
export const REGISTERED_COMMANDS = [
|
|
10
|
+
'init', 'build', 'themes', 'add', 'icons', 'blueprint', 'tokens',
|
|
11
|
+
'scan', 'prefix', 'scaffold', 'layout', 'perf', 'docs', 'meta',
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
export function loadCliManifest() {
|
|
15
|
+
const path = join(__dirname, '..', 'cli-manifest.json');
|
|
16
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function validateManifest(manifest) {
|
|
20
|
+
const errors = [];
|
|
21
|
+
const names = manifest.commands.map((c) => c.name);
|
|
22
|
+
for (const cmd of REGISTERED_COMMANDS) {
|
|
23
|
+
if (!names.includes(cmd)) {
|
|
24
|
+
errors.push(`Manifest missing command: ${cmd}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
for (const name of names) {
|
|
28
|
+
if (!REGISTERED_COMMANDS.includes(name)) {
|
|
29
|
+
errors.push(`Manifest has unknown command (not in router): ${name}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return errors;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function renderCliDocs(manifest) {
|
|
36
|
+
let md = banner('cli/cli-manifest.json');
|
|
37
|
+
md += heading(1, 'CLI commands');
|
|
38
|
+
md += `\nVelinStyle CLI v${manifest.version}. Run \`velinstyle --help\` for full usage.\n\n`;
|
|
39
|
+
md += table(
|
|
40
|
+
['Command', 'Summary', 'Subcommands', 'Flags', 'Example'],
|
|
41
|
+
manifest.commands.map((c) => [
|
|
42
|
+
`\`${c.name}\``,
|
|
43
|
+
c.summary,
|
|
44
|
+
(c.subcommands || []).join(', ') || '—',
|
|
45
|
+
(c.flags || []).join(', ') || '—',
|
|
46
|
+
`\`${c.example}\``,
|
|
47
|
+
]),
|
|
48
|
+
);
|
|
49
|
+
return md;
|
|
50
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, existsSync } from 'fs';
|
|
2
|
+
import { join, basename } from 'path';
|
|
3
|
+
import { banner, heading, table, bulletList, sortByKey } from './markdown.js';
|
|
4
|
+
import { loadComponentContracts, renderComponentA11ySection } from './extract-a11y.js';
|
|
5
|
+
|
|
6
|
+
function tagFromFile(file) {
|
|
7
|
+
return basename(file, '.js');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function parseBlockComment(source) {
|
|
11
|
+
const m = source.match(/^\/\*\*?([\s\S]*?)\*\//);
|
|
12
|
+
if (!m) return null;
|
|
13
|
+
return m[1]
|
|
14
|
+
.split('\n')
|
|
15
|
+
.map((l) => l.replace(/^\s*\* ?/, '').trimEnd())
|
|
16
|
+
.join('\n')
|
|
17
|
+
.trim();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseObservedAttributes(source) {
|
|
21
|
+
const m = source.match(/static\s+get\s+observedAttributes\s*\(\s*\)\s*\{\s*return\s*\[([^\]]*)\]/);
|
|
22
|
+
if (!m) return [];
|
|
23
|
+
return [...m[1].matchAll(/['"]([^'"]+)['"]/g)].map((x) => x[1]);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseEvents(source) {
|
|
27
|
+
const events = new Set();
|
|
28
|
+
const re = /CustomEvent\s*\(\s*['"]([^'"]+)['"]/g;
|
|
29
|
+
let m;
|
|
30
|
+
while ((m = re.exec(source)) !== null) events.add(m[1]);
|
|
31
|
+
return [...events].sort();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function parseParts(source) {
|
|
35
|
+
const parts = new Set();
|
|
36
|
+
const re = /part\s*=\s*["']([^"']+)["']/g;
|
|
37
|
+
let m;
|
|
38
|
+
while ((m = re.exec(source)) !== null) parts.add(m[1]);
|
|
39
|
+
return [...parts].sort();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseSlots(source) {
|
|
43
|
+
const slots = [];
|
|
44
|
+
const re = /<slot\b([^>]*)>/g;
|
|
45
|
+
let m;
|
|
46
|
+
while ((m = re.exec(source)) !== null) {
|
|
47
|
+
const attrs = m[1];
|
|
48
|
+
const nameM = attrs.match(/name\s*=\s*["']([^"']+)["']/);
|
|
49
|
+
slots.push(nameM ? nameM[1] : '(default)');
|
|
50
|
+
}
|
|
51
|
+
return [...new Set(slots)].sort();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function parsePublicApi(source) {
|
|
55
|
+
const methods = new Set();
|
|
56
|
+
const getters = new Set();
|
|
57
|
+
|
|
58
|
+
const classM = source.match(/class\s+\w+\s+extends\s+HTMLElement\s*\{([\s\S]*)\n\}/);
|
|
59
|
+
if (!classM) return { methods: [], getters: [] };
|
|
60
|
+
const body = classM[1];
|
|
61
|
+
|
|
62
|
+
const methodRe = /^\s{2}([a-zA-Z][\w]*)\s*\([^)]*\)\s*\{/gm;
|
|
63
|
+
let m;
|
|
64
|
+
while ((m = methodRe.exec(body)) !== null) {
|
|
65
|
+
const name = m[1];
|
|
66
|
+
if (name.startsWith('_') || name === 'constructor') continue;
|
|
67
|
+
if (['connectedCallback', 'disconnectedCallback', 'attributeChangedCallback'].includes(name)) continue;
|
|
68
|
+
methods.add(name);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const getRe = /^\s{2}get\s+([a-zA-Z][\w]*)\s*\(/gm;
|
|
72
|
+
while ((m = getRe.exec(body)) !== null) getters.add(m[1]);
|
|
73
|
+
|
|
74
|
+
const setRe = /^\s{2}set\s+([a-zA-Z][\w]*)\s*\(/gm;
|
|
75
|
+
while ((m = setRe.exec(body)) !== null) getters.add(`${m[1]} (setter)`);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
methods: [...methods].sort(),
|
|
79
|
+
getters: [...getters].sort(),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function extractComponentFile(filePath) {
|
|
84
|
+
const source = readFileSync(filePath, 'utf-8');
|
|
85
|
+
const tag = tagFromFile(filePath);
|
|
86
|
+
const { methods, getters } = parsePublicApi(source);
|
|
87
|
+
return {
|
|
88
|
+
tag,
|
|
89
|
+
file: `components/${basename(filePath)}`,
|
|
90
|
+
description: parseBlockComment(source),
|
|
91
|
+
observedAttributes: parseObservedAttributes(source),
|
|
92
|
+
events: parseEvents(source),
|
|
93
|
+
parts: parseParts(source),
|
|
94
|
+
slots: parseSlots(source),
|
|
95
|
+
methods,
|
|
96
|
+
getters,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function extractComponents(componentsDir) {
|
|
101
|
+
if (!existsSync(componentsDir)) return [];
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
const items = [];
|
|
104
|
+
for (const name of readdirSync(componentsDir)) {
|
|
105
|
+
if (!name.startsWith('velin-') || !name.endsWith('.js')) continue;
|
|
106
|
+
const key = name.toLowerCase();
|
|
107
|
+
if (seen.has(key)) continue;
|
|
108
|
+
seen.add(key);
|
|
109
|
+
items.push(extractComponentFile(join(componentsDir, name)));
|
|
110
|
+
}
|
|
111
|
+
return sortByKey(items, 'tag');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function renderComponent(meta, contracts) {
|
|
115
|
+
let md = banner(meta.file);
|
|
116
|
+
md += heading(1, `<${meta.tag}>`);
|
|
117
|
+
md += `\nSource: \`${meta.file}\`\n\n`;
|
|
118
|
+
|
|
119
|
+
if (meta.description) {
|
|
120
|
+
md += heading(2, 'Description');
|
|
121
|
+
md += `${meta.description}\n\n`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (contracts) {
|
|
125
|
+
md += renderComponentA11ySection(meta.tag, contracts);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
md += heading(2, 'Attributes');
|
|
129
|
+
if (meta.observedAttributes.length) {
|
|
130
|
+
md += table(
|
|
131
|
+
['Attribute', 'Notes'],
|
|
132
|
+
meta.observedAttributes.map((a) => [`\`${a}\``, 'Observed — triggers `attributeChangedCallback` when changed']),
|
|
133
|
+
);
|
|
134
|
+
} else {
|
|
135
|
+
md += '_No `observedAttributes` declared._\n\n';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
md += heading(2, 'Events');
|
|
139
|
+
md += bulletList(meta.events.map((e) => `\`${e}\` (bubbles)`));
|
|
140
|
+
|
|
141
|
+
md += heading(2, 'CSS parts');
|
|
142
|
+
md += bulletList(meta.parts.map((p) => `\`${p}\``));
|
|
143
|
+
|
|
144
|
+
md += heading(2, 'Slots');
|
|
145
|
+
md += bulletList(meta.slots.map((s) => `\`${s}\``));
|
|
146
|
+
|
|
147
|
+
md += heading(2, 'Public API');
|
|
148
|
+
const apiRows = [
|
|
149
|
+
...meta.methods.map((m) => ['Method', `\`${m}()\``]),
|
|
150
|
+
...meta.getters.map((g) => ['Property', `\`${g}\``]),
|
|
151
|
+
];
|
|
152
|
+
if (apiRows.length) {
|
|
153
|
+
md += table(['Kind', 'Name'], apiRows);
|
|
154
|
+
} else {
|
|
155
|
+
md += '_No public methods detected._\n';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return md;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function renderComponentsIndex(components) {
|
|
162
|
+
let md = banner('components/velin-*.js');
|
|
163
|
+
md += heading(1, 'Web Components');
|
|
164
|
+
md += '\nCustom elements in `components/`. Import via `@birdapi/velinstyle` or lazy-load with `./runtime`.\n\n';
|
|
165
|
+
md += table(
|
|
166
|
+
['Element', 'Attributes', 'Events', 'Reference'],
|
|
167
|
+
components.map((c) => [
|
|
168
|
+
`\`<${c.tag}>\``,
|
|
169
|
+
String(c.observedAttributes.length),
|
|
170
|
+
String(c.events.length),
|
|
171
|
+
`[${c.tag}.md](./${c.tag}.md)`,
|
|
172
|
+
]),
|
|
173
|
+
);
|
|
174
|
+
return md;
|
|
175
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { banner, heading, bulletList } from './markdown.js';
|
|
2
|
+
import { VELIN_META_MIME } from '../../core/meta/schema.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {object} bundle
|
|
6
|
+
*/
|
|
7
|
+
export function renderMetaReadme(bundle) {
|
|
8
|
+
let md = banner('velinstyle meta');
|
|
9
|
+
md += heading(1, 'Velin-Meta (agent context)');
|
|
10
|
+
md += '\n> **Do not edit manually.** Regenerate with `velinstyle meta` or `velinstyle docs generate --scope meta`.\n\n';
|
|
11
|
+
md += heading(2, 'MIME and files');
|
|
12
|
+
md += `\n- MIME: \`${VELIN_META_MIME}\`\n`;
|
|
13
|
+
md += '- Bundle: `dist/velin-agent.json`\n';
|
|
14
|
+
md += '- Index: `dist/llms.txt`\n\n';
|
|
15
|
+
md += heading(2, 'CLI');
|
|
16
|
+
md += '\n```bash\nnpx velinstyle meta\nnpx velinstyle meta --llms --base-url https://velinstyle.info\nnpx velinstyle meta page path/to/page.html\n```\n\n';
|
|
17
|
+
md += heading(2, 'Page embedding');
|
|
18
|
+
md += '\n```html\n<script type="' + VELIN_META_MIME + '" id="velin-meta">\n{\n "version": "' + bundle.framework.version + '",\n "page": { "intent": "component-doc" },\n "allowed": { "classesPrefix": ["velin-"] }\n}\n</script>\n```\n\n';
|
|
19
|
+
md += heading(2, 'Snapshot');
|
|
20
|
+
md += `\n- Framework: ${bundle.framework.name}@${bundle.framework.version}\n`;
|
|
21
|
+
md += `- Components: ${bundle.components.count}\n`;
|
|
22
|
+
md += `- Attributes: ${bundle.attributes.count}\n`;
|
|
23
|
+
md += `- CLI commands: ${bundle.cli.commands.length}\n`;
|
|
24
|
+
md += `- Scanner rules: ${bundle.tooling.scannerRuleCount}\n`;
|
|
25
|
+
if (bundle.searchIndex.entryCount != null) {
|
|
26
|
+
md += `- Search index entries: ${bundle.searchIndex.entryCount}\n`;
|
|
27
|
+
}
|
|
28
|
+
md += '\n' + heading(2, 'Conventions');
|
|
29
|
+
md += '\n' + bulletList(bundle.conventions);
|
|
30
|
+
md += '\n';
|
|
31
|
+
return md;
|
|
32
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, existsSync } from 'fs';
|
|
2
|
+
import { join, basename } from 'path';
|
|
3
|
+
import { SCANNER_RULES, PERF_RULES } from '../scanner-rules-data.js';
|
|
4
|
+
import { banner, heading, table, sortByKey } from './markdown.js';
|
|
5
|
+
|
|
6
|
+
const VELIN_SELECTOR_RE = /\.(velin-[\w-]+)/g;
|
|
7
|
+
|
|
8
|
+
function firstComment(content) {
|
|
9
|
+
const m = content.match(/\/\*\s*([^*]+?)\s*\*\//);
|
|
10
|
+
return m ? m[1].trim() : null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function extractA11yModules(srcDir) {
|
|
14
|
+
const a11yDir = join(srcDir, 'a11y');
|
|
15
|
+
if (!existsSync(a11yDir)) return [];
|
|
16
|
+
const modules = [];
|
|
17
|
+
for (const file of readdirSync(a11yDir).filter((f) => f.endsWith('.css')).sort()) {
|
|
18
|
+
const content = readFileSync(join(a11yDir, file), 'utf-8');
|
|
19
|
+
const selectors = new Set();
|
|
20
|
+
let m;
|
|
21
|
+
const re = new RegExp(VELIN_SELECTOR_RE.source, 'g');
|
|
22
|
+
while ((m = re.exec(content)) !== null) selectors.add(m[1]);
|
|
23
|
+
modules.push({
|
|
24
|
+
name: basename(file, '.css'),
|
|
25
|
+
file: `src/a11y/${file}`,
|
|
26
|
+
description: firstComment(content),
|
|
27
|
+
selectors: [...selectors].sort(),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return modules;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function renderScannerRules() {
|
|
34
|
+
const all = sortByKey([...SCANNER_RULES, ...PERF_RULES], 'id');
|
|
35
|
+
let md = banner('cli/scanner-rules-data.js');
|
|
36
|
+
md += heading(1, 'Scanner rules');
|
|
37
|
+
md += '\nRun `velinstyle scan [path]` for security, a11y, CSS, and PII checks. `velinstyle perf audit` for performance.\n\n';
|
|
38
|
+
md += '```bash\nvelinstyle scan . --severity warning\nvelinstyle scan . --only pii --fix-dry-run\nvelinstyle perf audit samples/\n```\n\n';
|
|
39
|
+
|
|
40
|
+
const categories = [...new Set(all.map((r) => r.category))].sort();
|
|
41
|
+
for (const cat of categories) {
|
|
42
|
+
const rules = all.filter((r) => r.category === cat);
|
|
43
|
+
md += heading(2, cat);
|
|
44
|
+
md += table(
|
|
45
|
+
['Rule ID', 'Severity', 'Message', 'Fix hint'],
|
|
46
|
+
rules.map((r) => [`\`${r.id}\``, r.severity, r.message, r.fixHint || '—']),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return md;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function renderA11yModules(modules) {
|
|
53
|
+
let md = banner('src/a11y/*.css');
|
|
54
|
+
md += heading(1, 'Accessibility CSS modules');
|
|
55
|
+
md += '\nImported in `@layer a11y` from `src/velinstyle.css`.\n\n';
|
|
56
|
+
md += table(
|
|
57
|
+
['Module', 'Selectors', 'Reference'],
|
|
58
|
+
modules.map((m) => [m.name, String(m.selectors.length), `\`${m.file}\``]),
|
|
59
|
+
);
|
|
60
|
+
md += '\n';
|
|
61
|
+
for (const m of modules) {
|
|
62
|
+
md += heading(2, m.name);
|
|
63
|
+
if (m.description) md += `${m.description}\n\n`;
|
|
64
|
+
md += `Source: \`${m.file}\`\n\n`;
|
|
65
|
+
if (m.selectors.length) {
|
|
66
|
+
md += bulletListSelectors(m.selectors);
|
|
67
|
+
} else {
|
|
68
|
+
md += '_No `.velin-*` class selectors (may use element/attribute selectors)._\n\n';
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return md;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function bulletListSelectors(items) {
|
|
75
|
+
return `${items.map((s) => `- \`.${s}\``).join('\n')}\n\n`;
|
|
76
|
+
}
|