srcdev-nuxt-components 9.4.4 → 9.4.6
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/.claude/commands/migrate-component.md +106 -0
- package/.claude/component-ledger/artifact-url.txt +1 -0
- package/.claude/component-ledger/audit.json +1 -0
- package/.claude/component-ledger/build.mjs +111 -0
- package/.claude/component-ledger/output.html +559 -0
- package/.claude/component-ledger/template.html +559 -0
- package/.claude/hooks/refresh-component-ledger.sh +32 -0
- package/.claude/settings.json +10 -0
- package/.claude/skills/components/animated-svg-text.md +78 -0
- package/.claude/skills/components/breadcrumb.md +1 -0
- package/.claude/skills/components/canvas-switcher.md +61 -0
- package/.claude/skills/components/clip-element.md +67 -0
- package/.claude/skills/components/clipped-panel.md +64 -0
- package/.claude/skills/components/content-docs.md +2 -0
- package/.claude/skills/components/deep-expanding-menu-classic.md +94 -0
- package/.claude/skills/components/deep-expanding-menu.md +92 -0
- package/.claude/skills/components/display-banner.md +60 -0
- package/.claude/skills/components/display-tooltip-defined.md +139 -0
- package/.claude/skills/components/display-tooltip.md +85 -0
- package/.claude/skills/components/marquee-scroller.md +130 -0
- package/.claude/skills/components/navigation-items.md +1 -0
- package/.claude/skills/components/responsive-header.md +3 -0
- package/.claude/skills/components/site-header.md +4 -0
- package/.claude/skills/components/site-navigation.md +1 -0
- package/.claude/skills/components/tab-navigation.md +1 -0
- package/.claude/skills/composable-tooltips-guide.md +10 -0
- package/.claude/skills/index.md +8 -1
- package/.claude/skills/storybook-add-story.md +30 -0
- package/.vscode/srcdev-component-animated-svg-text.code-snippets +15 -0
- package/.vscode/srcdev-component-breadcrumb.code-snippets +13 -0
- package/.vscode/srcdev-component-canvas-switcher.code-snippets +9 -0
- package/.vscode/srcdev-component-clip-element.code-snippets +20 -0
- package/.vscode/srcdev-component-clipped-panel.code-snippets +23 -0
- package/.vscode/srcdev-component-content-docs.code-snippets +18 -0
- package/.vscode/srcdev-component-deep-expanding-menu-classic.code-snippets +9 -0
- package/.vscode/srcdev-component-deep-expanding-menu.code-snippets +9 -0
- package/.vscode/srcdev-component-display-banner.code-snippets +30 -0
- package/.vscode/srcdev-component-display-tooltip-defined.code-snippets +29 -0
- package/.vscode/srcdev-component-display-tooltip.code-snippets +38 -0
- package/.vscode/srcdev-component-marquee-scroller.code-snippets +93 -0
- package/.vscode/srcdev-component-responsive-header.code-snippets +12 -0
- package/.vscode/srcdev-component-site-header.code-snippets +17 -0
- package/.vscode/srcdev-component-site-navigation.code-snippets +30 -0
- package/.vscode/srcdev-component-slider-gallery.code-snippets +38 -0
- package/.vscode/srcdev-component-tab-navigation.code-snippets +30 -0
- package/app/components/01.atoms/animations/animated-svg-text/AnimatedSvgText.vue +58 -0
- package/app/components/01.atoms/animations/animated-svg-text/CONSUMER-STYLING.md +34 -0
- package/app/components/01.atoms/animations/animated-svg-text/stories/AnimatedSvgText.stories.ts +69 -0
- package/app/components/01.atoms/animations/animated-svg-text/tests/AnimatedSvgText.spec.ts +63 -0
- package/app/components/01.atoms/animations/animated-svg-text/tests/__snapshots__/AnimatedSvgText.spec.ts.snap +7 -0
- package/app/components/01.atoms/animations/clip-element/CONSUMER-STYLING.md +27 -0
- package/app/components/{clip-element → 01.atoms/animations/clip-element}/ClipElement.vue +16 -11
- package/app/components/01.atoms/animations/clip-element/stories/ClipElement.stories.ts +133 -0
- package/app/components/01.atoms/animations/clip-element/tests/ClipElement.spec.ts +70 -0
- package/app/components/01.atoms/animations/clip-element/tests/__snapshots__/ClipElement.spec.ts.snap +7 -0
- package/app/components/01.atoms/animations/marquee-scroller/CONSUMER-STYLING.md +94 -0
- package/app/components/01.atoms/animations/marquee-scroller/MarqueeScroller.vue +331 -0
- package/app/components/01.atoms/animations/marquee-scroller/stories/MarqueeScroller.stories.ts +151 -0
- package/app/components/01.atoms/animations/marquee-scroller/tests/MarqueeScroller.spec.ts +315 -0
- package/app/components/01.atoms/animations/marquee-scroller/tests/__snapshots__/MarqueeScroller.spec.ts.snap +28 -0
- package/app/components/01.atoms/canvas-switcher/CONSUMER-STYLING.md +27 -0
- package/app/components/01.atoms/canvas-switcher/CanvasSwitcher.vue +111 -0
- package/app/components/01.atoms/canvas-switcher/stories/CanvasSwitcher.stories.ts +75 -0
- package/app/components/01.atoms/canvas-switcher/tests/CanvasSwitcher.spec.ts +67 -0
- package/app/components/01.atoms/clipped-panel/CONSUMER-STYLING.md +39 -0
- package/app/components/01.atoms/clipped-panel/ClippedPanel.vue +68 -0
- package/app/components/01.atoms/clipped-panel/stories/ClippedPanel.stories.ts +105 -0
- package/app/components/01.atoms/clipped-panel/tests/ClippedPanel.spec.ts +67 -0
- package/app/components/01.atoms/clipped-panel/tests/__snapshots__/ClippedPanel.spec.ts.snap +3 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/ContentDocs.vue +8 -2
- package/app/components/01.atoms/display-banner/CONSUMER-STYLING.md +35 -0
- package/app/components/{display-banner → 01.atoms/display-banner}/DisplayBanner.vue +13 -35
- package/app/components/01.atoms/display-banner/stories/DisplayBanner.stories.ts +100 -0
- package/app/components/01.atoms/display-banner/tests/DisplayBanner.spec.ts +78 -0
- package/app/components/01.atoms/display-banner/tests/__snapshots__/DisplayBanner.spec.ts.snap +8 -0
- package/app/components/01.atoms/display-tooltip/CONSUMER-STYLING.md +62 -0
- package/app/components/01.atoms/display-tooltip/DisplayTooltip.vue +188 -0
- package/app/components/01.atoms/display-tooltip/stories/DisplayTooltip.stories.ts +94 -0
- package/app/components/01.atoms/display-tooltip/tests/DisplayTooltip.spec.ts +75 -0
- package/app/components/01.atoms/display-tooltip/tests/__snapshots__/DisplayTooltip.spec.ts.snap +12 -0
- package/app/components/01.atoms/navigation/breadcrumb/Breadcrumb.vue +4 -1
- package/app/components/02.molecules/display-tooltip-defined/CONSUMER-STYLING.md +42 -0
- package/app/components/02.molecules/display-tooltip-defined/DisplayTooltipDefined.vue +116 -0
- package/app/components/02.molecules/display-tooltip-defined/stories/DisplayTooltipDefined.stories.ts +126 -0
- package/app/components/02.molecules/display-tooltip-defined/tests/DisplayTooltipDefined.spec.ts +66 -0
- package/app/components/02.molecules/display-tooltip-defined/tests/__snapshots__/DisplayTooltipDefined.spec.ts.snap +17 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu/CONSUMER-STYLING.md +44 -0
- package/app/components/{deep-expanding-menu → 02.molecules/navigation/deep-expanding-menu}/DeepExpandingMenu.vue +53 -64
- package/app/components/02.molecules/navigation/deep-expanding-menu/stories/DeepExpandingMenu.stories.ts +79 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu/tests/DeepExpandingMenu.spec.ts +92 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu/tests/__snapshots__/DeepExpandingMenu.spec.ts.snap +17 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu-classic/CONSUMER-STYLING.md +40 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu-classic/DeepExpandingMenuClassic.vue +200 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu-classic/stories/DeepExpandingMenuClassic.stories.ts +79 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu-classic/tests/DeepExpandingMenuClassic.spec.ts +82 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu-classic/tests/__snapshots__/DeepExpandingMenuClassic.spec.ts.snap +18 -0
- package/app/components/02.molecules/navigation/site-navigation/SiteNavigation.vue +4 -1
- package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +4 -1
- package/app/components/03.organisms/image-galleries/slider-gallery/SliderGallery.vue +16 -4
- package/app/components/03.organisms/responsive-header/NavigationItems.vue +4 -1
- package/app/components/03.organisms/responsive-header/ResponsiveHeader.vue +16 -3
- package/app/components/03.organisms/site-header/SiteHeader.vue +16 -1
- package/app/components/03.organisms/site-header/tests/__snapshots__/SiteHeader.spec.ts.snap +1 -1
- package/app/types/components/display-tooltip-defined.d.ts +10 -0
- package/app/types/components/index.ts +2 -0
- package/app/types/components/marquee-scroller.d.ts +10 -0
- package/package.json +1 -1
- package/app/components/animated-svg-text/AnimatedSvgText.vue +0 -89
- package/app/components/canvas-switcher/CanvasSwitcher.vue +0 -104
- package/app/components/clipped-panels/ClippedPanel.vue +0 -87
- package/app/components/deep-expanding-menu/DeepExpandingMenuOld.vue +0 -218
- package/app/components/display-details/DisplayDetailsCore.vue +0 -122
- package/app/components/display-tooltip/DisplayTooltip.vue +0 -170
- package/app/components/display-tooltip/DisplayTooltipDefined.vue +0 -103
- package/app/components/magnetic-navigation/MagneticNavigation.vue +0 -162
- package/app/components/marquee-scroller/MarqueeScroller.vue +0 -289
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Bring one component up to the current compliance standard (tier, styling doc, tokens, tests, story, skill doc, snippet)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Migrate a single component to full compliance with the standard in CLAUDE.md (Development
|
|
6
|
+
Workflow, Styling Methodology, Vue Template Conventions) — see also `project_component_compliance_standard`
|
|
7
|
+
and `feedback_private_token_convention_clarified` in memory for the token rule specifically.
|
|
8
|
+
|
|
9
|
+
## 1. Pick the component
|
|
10
|
+
|
|
11
|
+
If the user gave an argument (a component name or path), resolve it against `app/components/`
|
|
12
|
+
(match on folder name or `.vue` filename, case-insensitively). If it doesn't resolve uniquely,
|
|
13
|
+
ask which one they meant.
|
|
14
|
+
|
|
15
|
+
Otherwise, auto-pick the next worst offender:
|
|
16
|
+
|
|
17
|
+
1. Run `node .claude/component-ledger/build.mjs` to refresh the audit data.
|
|
18
|
+
2. Read `.claude/component-ledger/audit.json`. Pick in this priority order, first match wins:
|
|
19
|
+
- Any group with `"tier": "NONE"` (unplaced) — pick the one with the lowest `score`, ties broken alphabetically by `compdir`.
|
|
20
|
+
- Else any group with `"variants": true` — same tie-break.
|
|
21
|
+
- Else any group with `"legacy_props": true` (still options-style `defineProps({...})`, not
|
|
22
|
+
`defineProps<Props>()`) — same tie-break. This one doesn't move the 5-point `score`, so it
|
|
23
|
+
would otherwise hide forever behind an already-complete-looking component.
|
|
24
|
+
- Else the lowest `score` overall — same tie-break.
|
|
25
|
+
3. State which component was picked and why in one line (e.g. "Picked `input-select` — unplaced isn't the issue here, it forks a `variants/` subfolder and scores 2/5.") before doing anything else, so the user can redirect you if they'd rather do a different one next.
|
|
26
|
+
|
|
27
|
+
## 2. Confirm it's still wanted
|
|
28
|
+
|
|
29
|
+
Before starting the checklist, confirm with the user that this component should actually be
|
|
30
|
+
migrated — a low score isn't proof it's still needed. Use AskUserQuestion with these options:
|
|
31
|
+
|
|
32
|
+
- **Migrate it** (recommended default) — proceed to step 3.
|
|
33
|
+
- **Leave it untouched** — skip it this run. If it was auto-picked, say so and go back to step 1
|
|
34
|
+
to pick the next worst offender instead; if the user named it explicitly, just stop.
|
|
35
|
+
- **Delete it** — it's unused, superseded by another component, or otherwise no longer wanted.
|
|
36
|
+
Run the `check-component-usage` skill against the component's name first, across every consumer
|
|
37
|
+
repo, and report the results before deleting anything. A clean scan is good evidence, not proof
|
|
38
|
+
(see the skill's own caveat on dynamic `:is` usage etc.) — if it finds a real consumer, surface
|
|
39
|
+
that back to the user with an `AskUserQuestion` rather than auto-aborting or auto-proceeding;
|
|
40
|
+
the user may still want it deleted (e.g. the consumer repo is itself defunct or being retired).
|
|
41
|
+
Once confirmed, delete the component file(s) and every trace this command would otherwise have
|
|
42
|
+
created or touched for it — tests, stories, `CONSUMER-STYLING.md`, skill doc, VS Code snippet,
|
|
43
|
+
any `.claude/skills/index.md` entry, and any direct references elsewhere in the repo (e.g. a
|
|
44
|
+
`MIGRATION.md` row) — then skip the rest of this command for that component.
|
|
45
|
+
|
|
46
|
+
## 3. Work the checklist
|
|
47
|
+
|
|
48
|
+
Go through each point below. Skip a point only when it genuinely doesn't apply (state why,
|
|
49
|
+
briefly) — don't skip silently.
|
|
50
|
+
|
|
51
|
+
1. **Tier folder** — if the component lives outside `01.atoms`–`05.forms`, move it with `git mv`
|
|
52
|
+
into the tier that fits (see `project_component_tiers` in memory for what each tier means).
|
|
53
|
+
If none fits cleanly, ask the user rather than guessing.
|
|
54
|
+
2. **Props pattern** — confirm `interface Props` + `withDefaults(defineProps<Props>(), {...})`,
|
|
55
|
+
not options-style `defineProps({...})`. Migrate if needed.
|
|
56
|
+
3. **CSS tokens** — audit every custom property in the component's `<style>` block against the
|
|
57
|
+
corrected rule (consumer relevance, not reuse count):
|
|
58
|
+
- A value a consumer could plausibly want to override — including a per-state variant like a
|
|
59
|
+
hover-only width or a dark-theme colour — must be a **public** token (`--component-name-x`),
|
|
60
|
+
consumed directly at its point of use, even if used only once.
|
|
61
|
+
- A value with no plausible consumer relevance stays **private** (`--_x`), even if used only
|
|
62
|
+
once — don't strip the prefix just because reuse is low.
|
|
63
|
+
- Fix the actual bug class this catches: a consumer-relevant value that's currently private
|
|
64
|
+
with no public fallback. That's the thing to promote, not every `--_` var you find.
|
|
65
|
+
4. **CONSUMER-STYLING.md** — create or update so every public token the component exposes is
|
|
66
|
+
documented, with its default. Skip only if the component genuinely has no override surface at
|
|
67
|
+
all (no CSS custom properties, no class passthrough).
|
|
68
|
+
5. **Tests** — create or bring up to date in `tests/`, following the Testing Requirements section
|
|
69
|
+
(mountSuspended, fake-timer rules, etc.). Skip only for a trivial presentational component with
|
|
70
|
+
no logic worth testing — say so explicitly if you skip.
|
|
71
|
+
6. **Storybook story** — create or update `stories/*.stories.ts` with controls for props/slots
|
|
72
|
+
that warrant them (see `.claude/skills/storybook-add-story.md`).
|
|
73
|
+
7. **Skill doc** — create or update `.claude/skills/components/<component-name>.md`. If the
|
|
74
|
+
component still forks `variants/` files, fold each variant's behaviour into this doc as a
|
|
75
|
+
"Variants" section per `feedback_variants_deprecated_as_own_skill_docs` — don't delete the
|
|
76
|
+
variant files yourself without asking, since consumers may still import them directly; flag it
|
|
77
|
+
to the user as a follow-up decision instead.
|
|
78
|
+
8. **VS Code snippet** — create or update `.vscode/srcdev-component-{name}.code-snippets`.
|
|
79
|
+
9. **Accessibility** — check for gaps beyond what already-passing tests would catch:
|
|
80
|
+
- Interactive controls (buttons, toggles, custom form-like widgets) have an accessible name —
|
|
81
|
+
visible text, `aria-label`, or `aria-labelledby`.
|
|
82
|
+
- Keyboard behaviour matches what's actually implemented — no keydown case that only calls
|
|
83
|
+
`event.preventDefault()` with a comment like "could add this later", and no screen-reader
|
|
84
|
+
copy (visible or `sr-only`) that describes an interaction the component doesn't actually
|
|
85
|
+
perform. Cross-check every claim in the copy against the handler that's supposed to back it.
|
|
86
|
+
- Focus is visible (`:focus-visible`, not a suppressed outline) on anything focusable.
|
|
87
|
+
- Live-updating or auto-advancing content (carousels, marquees, auto-dismissing toasts) has a
|
|
88
|
+
way to pause it, per WCAG 2.2.2 — a visible control, or pause-on-hover/focus at minimum.
|
|
89
|
+
- `prefers-reduced-motion` is respected for any animation that isn't purely decorative.
|
|
90
|
+
10. **Localisation (no hardcoded consumer-facing text)** — grep the template and script for
|
|
91
|
+
user-visible string literals (button copy, `aria-label`/`aria-description` text, placeholder
|
|
92
|
+
text, empty-state messages, etc.) that aren't already props. This library has no i18n
|
|
93
|
+
framework dependency (see `MarqueeScroller`'s `playLabel`/`pauseLabel`/`ariaLabel`/
|
|
94
|
+
`ariaDescription` for the pattern) — promote any hardcoded copy to a string prop with the
|
|
95
|
+
existing English text as its default, so a consumer can pass translated strings from their own
|
|
96
|
+
i18n solution. Icon-only controls should also get an icon-override prop or slot (see
|
|
97
|
+
`playIcon`/`pauseIcon`/`toggle-icon`) alongside the label prop, not just the label.
|
|
98
|
+
|
|
99
|
+
## 4. Wrap up
|
|
100
|
+
|
|
101
|
+
- Run the relevant test file(s) and `npx vue-tsc` (or the project's usual type-check command) to
|
|
102
|
+
confirm nothing broke.
|
|
103
|
+
- Summarize what changed and what you deliberately skipped (with reasons).
|
|
104
|
+
- Don't stage, commit, or push — that's the user's call. Mention that running
|
|
105
|
+
`/create-commit-message` next will trigger the Component Ledger refresh automatically via the
|
|
106
|
+
existing hook, since this touches `app/components/`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
https://claude.ai/code/artifact/d3c33630-20d5-4fda-b9df-2ba2ee7f8256
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"auditedAt":"2026-09-08","rows":[{"compdir":"01.atoms/animations/animated-svg-text","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":0,"score":5},{"compdir":"01.atoms/animations/clip-element","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":1,"score":5},{"compdir":"01.atoms/animations/entry","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":true,"skill":false,"snippet":false,"priv_tokens":0,"score":1},{"compdir":"01.atoms/animations/marquee-scroller","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":2,"score":5},{"compdir":"01.atoms/animations/scroll-reveal-frame","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":3,"score":3},{"compdir":"01.atoms/animations/scroll-reveal-image","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":1,"score":3},{"compdir":"01.atoms/banner-video","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":4,"score":5},{"compdir":"01.atoms/canvas-switcher","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":0,"score":5},{"compdir":"01.atoms/card","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":13,"score":5},{"compdir":"01.atoms/clipped-panel","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":1,"score":5},{"compdir":"01.atoms/content-wrappers/content-columns-2","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":false,"snippet":false,"priv_tokens":0,"score":2},{"compdir":"01.atoms/content-wrappers/content-width","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":false,"snippet":false,"priv_tokens":0,"score":2},{"compdir":"01.atoms/content-wrappers/docs-pages","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":51,"score":4},{"compdir":"01.atoms/content-wrappers/layout-grid/layout-grid-by-cols","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":1,"score":3},{"compdir":"01.atoms/content-wrappers/layout-grid/layout-grid-by-width","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":false,"snippet":false,"priv_tokens":1,"score":2},{"compdir":"01.atoms/cookie-consent-banner","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":7,"score":3},{"compdir":"01.atoms/display-avatar","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":0,"score":3},{"compdir":"01.atoms/display-banner","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":0,"score":5},{"compdir":"01.atoms/display-dialog","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":21,"score":4},{"compdir":"01.atoms/display-pill","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":14,"score":3},{"compdir":"01.atoms/display-tooltip","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":1,"score":5},{"compdir":"01.atoms/glass-panel","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":true,"snippet":false,"priv_tokens":4,"score":1},{"compdir":"01.atoms/grids/data-grid","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":0,"score":3},{"compdir":"01.atoms/grids/grid-stack","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":0,"score":3},{"compdir":"01.atoms/navigation/breadcrumb","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":7,"score":5},{"compdir":"01.atoms/page-row","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":5,"score":4},{"compdir":"01.atoms/prompt","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":0,"score":4},{"compdir":"01.atoms/qr-code","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":0,"score":3},{"compdir":"01.atoms/text-block","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":0},{"compdir":"01.atoms/text-blocks/eyebrow-text","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":0,"score":3},{"compdir":"01.atoms/text-blocks/hero-text","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":1,"score":4},{"compdir":"01.atoms/text-blocks/link-text","tier":"01.atoms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":0,"score":3},{"compdir":"01.atoms/toast","tier":"01.atoms","n_vue":2,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":6,"score":5},{"compdir":"02.molecules/action-menu","tier":"02.molecules","n_vue":2,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":21,"score":4},{"compdir":"02.molecules/alert-content","tier":"02.molecules","n_vue":2,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":1,"score":3},{"compdir":"02.molecules/alert-masked-content","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":false,"snippet":false,"priv_tokens":1,"score":2},{"compdir":"02.molecules/display-chip","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":1,"score":3},{"compdir":"02.molecules/display-tooltip-defined","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":0,"score":5},{"compdir":"02.molecules/expandable/accordian","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":0,"score":5},{"compdir":"02.molecules/expandable/expanding-panel","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":0,"score":5},{"compdir":"02.molecules/expandable/expanding-panel-classic","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":0,"score":5},{"compdir":"02.molecules/input-copy","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":16,"score":5},{"compdir":"02.molecules/navigation/deep-expanding-menu","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":2,"score":5},{"compdir":"02.molecules/navigation/deep-expanding-menu-classic","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":1,"score":5},{"compdir":"02.molecules/navigation/navigation-horizontal","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":20,"score":3},{"compdir":"02.molecules/navigation/site-navigation","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":45,"score":4},{"compdir":"02.molecules/navigation/tab-navigation","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":28,"score":5},{"compdir":"02.molecules/price-list","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":false,"snippet":false,"priv_tokens":8,"score":2},{"compdir":"02.molecules/pricing-card","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":28,"score":5},{"compdir":"02.molecules/profile-section","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":0,"score":3},{"compdir":"02.molecules/qr-code","tier":"02.molecules","n_vue":2,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":0,"score":3},{"compdir":"02.molecules/samaritan-prompt","tier":"02.molecules","n_vue":2,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":false,"skill":true,"snippet":false,"priv_tokens":14,"score":2},{"compdir":"02.molecules/social-icons-list","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":2,"score":3},{"compdir":"02.molecules/stepper-list","tier":"02.molecules","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":22,"score":4},{"compdir":"03.organisms/colour-finder","tier":"03.organisms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":20,"score":0},{"compdir":"03.organisms/image-galleries/slider-gallery","tier":"03.organisms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":false,"snippet":true,"priv_tokens":12,"score":3},{"compdir":"03.organisms/responsive-header","tier":"03.organisms","n_vue":2,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":18,"score":5},{"compdir":"03.organisms/services/service-detail","tier":"03.organisms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":0,"score":5},{"compdir":"03.organisms/services/service-summary","tier":"03.organisms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":1,"score":5},{"compdir":"03.organisms/services/services-card","tier":"03.organisms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":0,"score":5},{"compdir":"03.organisms/services/services-grids","tier":"03.organisms","n_vue":2,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":0,"score":3},{"compdir":"03.organisms/site-header","tier":"03.organisms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":true,"snippet":true,"priv_tokens":0,"score":5},{"compdir":"04.templates/page-hero-highlights","tier":"04.templates","n_vue":2,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":0,"score":3},{"compdir":"05.forms/form-errors","tier":"05.forms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":1},{"compdir":"05.forms/form-field","tier":"05.forms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":4,"score":0},{"compdir":"05.forms/form-fieldset","tier":"05.forms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":0},{"compdir":"05.forms/form-wrapper","tier":"05.forms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":0},{"compdir":"05.forms/input-button","tier":"05.forms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":false,"snippet":false,"priv_tokens":2,"score":3},{"compdir":"05.forms/input-checkbox","tier":"05.forms","n_vue":2,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":1},{"compdir":"05.forms/input-checkbox-radio","tier":"05.forms","n_vue":3,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":true,"stories":true,"skill":false,"snippet":false,"priv_tokens":3,"score":3},{"compdir":"05.forms/input-description","tier":"05.forms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":1},{"compdir":"05.forms/input-label","tier":"05.forms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":1},{"compdir":"05.forms/input-number","tier":"05.forms","n_vue":2,"variants":true,"legacy_props":false,"consumer_styling":true,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":4,"score":1},{"compdir":"05.forms/input-radio","tier":"05.forms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":1},{"compdir":"05.forms/input-range","tier":"05.forms","n_vue":2,"variants":true,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":0},{"compdir":"05.forms/input-range-fancy","tier":"05.forms","n_vue":2,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":0},{"compdir":"05.forms/input-select","tier":"05.forms","n_vue":2,"variants":true,"legacy_props":false,"consumer_styling":true,"tests":false,"stories":true,"skill":false,"snippet":false,"priv_tokens":6,"score":2},{"compdir":"05.forms/input-text","tier":"05.forms","n_vue":4,"variants":true,"legacy_props":false,"consumer_styling":true,"tests":false,"stories":true,"skill":false,"snippet":false,"priv_tokens":5,"score":2},{"compdir":"05.forms/input-textarea","tier":"05.forms","n_vue":2,"variants":true,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":true,"skill":false,"snippet":false,"priv_tokens":0,"score":1},{"compdir":"05.forms/pending-effect","tier":"05.forms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":0},{"compdir":"05.forms/toggle-switch","tier":"05.forms","n_vue":3,"variants":true,"legacy_props":false,"consumer_styling":true,"tests":false,"stories":true,"skill":false,"snippet":true,"priv_tokens":15,"score":3},{"compdir":"05.forms/triple-toggle-switch","tier":"05.forms","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":true,"tests":false,"stories":true,"skill":false,"snippet":false,"priv_tokens":11,"score":2},{"compdir":"alert-mask","tier":"NONE","n_vue":1,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":true,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":1},{"compdir":"carousels","tier":"NONE","n_vue":3,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":true,"stories":true,"skill":true,"snippet":false,"priv_tokens":6,"score":3},{"compdir":"container-glow","tier":"NONE","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":true,"stories":true,"skill":false,"snippet":false,"priv_tokens":0,"score":2},{"compdir":"display-theme-switch","tier":"NONE","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":true,"skill":false,"snippet":false,"priv_tokens":8,"score":1},{"compdir":"glowing-border","tier":"NONE","n_vue":1,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":false,"stories":true,"skill":false,"snippet":false,"priv_tokens":0,"score":1},{"compdir":"layout-grids","tier":"NONE","n_vue":2,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":true,"stories":true,"skill":false,"snippet":false,"priv_tokens":3,"score":2},{"compdir":"masonry-grid","tier":"NONE","n_vue":1,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":4,"score":0},{"compdir":"masonry-grid-ordered","tier":"NONE","n_vue":2,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":false,"stories":true,"skill":false,"snippet":false,"priv_tokens":12,"score":1},{"compdir":"masonry-grid-sorted","tier":"NONE","n_vue":1,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":3,"score":0},{"compdir":"parallax","tier":"NONE","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":true,"snippet":false,"priv_tokens":0,"score":1},{"compdir":"pop-over","tier":"NONE","n_vue":1,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":0},{"compdir":"rotating-carousel","tier":"NONE","n_vue":1,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":5,"score":0},{"compdir":"skip-links","tier":"NONE","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":0},{"compdir":"tabs","tier":"NONE","n_vue":1,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":11,"score":0},{"compdir":"test-storybook","tier":"NONE","n_vue":1,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":false,"stories":true,"skill":false,"snippet":false,"priv_tokens":0,"score":1},{"compdir":"typography","tier":"NONE","n_vue":1,"variants":false,"legacy_props":false,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":0},{"compdir":"ui-block-decorated","tier":"NONE","n_vue":1,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":0},{"compdir":"view-timeline","tier":"NONE","n_vue":1,"variants":false,"legacy_props":true,"consumer_styling":false,"tests":false,"stories":false,"skill":false,"snippet":false,"priv_tokens":0,"score":0}]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Regenerates .claude/component-ledger/audit.json (raw data) and output.html (ready to
|
|
2
|
+
// publish as the Component Ledger artifact) from the current state of the repo.
|
|
3
|
+
//
|
|
4
|
+
// Run from the repo root: node .claude/component-ledger/build.mjs
|
|
5
|
+
//
|
|
6
|
+
// Checked against the standard in memory (project_component_compliance_standard.md) and
|
|
7
|
+
// CLAUDE.md's Development Workflow / Styling Methodology sections.
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
|
|
12
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const root = path.resolve(here, "../.."); // repo root
|
|
14
|
+
const componentsRoot = path.join(root, "app/components");
|
|
15
|
+
|
|
16
|
+
function walk(dir, out = []) {
|
|
17
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
18
|
+
const full = path.join(dir, entry.name);
|
|
19
|
+
if (entry.isDirectory()) walk(full, out);
|
|
20
|
+
else if (entry.name.endsWith(".vue")) out.push(full);
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const vueFiles = walk(componentsRoot).filter(
|
|
26
|
+
(f) => !f.split(path.sep).includes("tests") && !f.split(path.sep).includes("stories")
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
function toKebab(name) {
|
|
30
|
+
return name.replace(/(?<!^)(?=[A-Z])/g, "-").toLowerCase();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const skillsDir = path.join(root, ".claude/skills/components");
|
|
34
|
+
const skills = new Set(
|
|
35
|
+
fs.existsSync(skillsDir)
|
|
36
|
+
? fs.readdirSync(skillsDir).filter((f) => f.endsWith(".md")).map((f) => f.slice(0, -3))
|
|
37
|
+
: []
|
|
38
|
+
);
|
|
39
|
+
const vscodeDir = path.join(root, ".vscode");
|
|
40
|
+
const snippets = fs.existsSync(vscodeDir)
|
|
41
|
+
? fs.readdirSync(vscodeDir).filter((f) => f.endsWith(".code-snippets"))
|
|
42
|
+
: [];
|
|
43
|
+
|
|
44
|
+
const groups = new Map();
|
|
45
|
+
for (const vf of vueFiles) {
|
|
46
|
+
const d = path.dirname(vf);
|
|
47
|
+
const base = path.basename(d);
|
|
48
|
+
const compdir = base === "variants" ? path.dirname(d) : d;
|
|
49
|
+
if (!groups.has(compdir)) groups.set(compdir, []);
|
|
50
|
+
groups.get(compdir).push(vf);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const rows = [];
|
|
54
|
+
for (const [compdir, files] of [...groups.entries()].sort()) {
|
|
55
|
+
const relDir = path.relative(componentsRoot, compdir);
|
|
56
|
+
const tierMatch = compdir.match(/app\/components\/(0\d\.\w+)\//);
|
|
57
|
+
const tier = tierMatch ? tierMatch[1] : "NONE";
|
|
58
|
+
const hasConsumerStyling = fs.existsSync(path.join(compdir, "CONSUMER-STYLING.md"));
|
|
59
|
+
const hasTests =
|
|
60
|
+
fs.existsSync(path.join(compdir, "tests")) && fs.statSync(path.join(compdir, "tests")).isDirectory();
|
|
61
|
+
const hasStoriesDir =
|
|
62
|
+
fs.existsSync(path.join(compdir, "stories")) && fs.statSync(path.join(compdir, "stories")).isDirectory();
|
|
63
|
+
const hasStoriesFile = fs.readdirSync(compdir).some((f) => f.endsWith(".stories.ts"));
|
|
64
|
+
const vueNames = files.map((f) => toKebab(path.basename(f, ".vue")));
|
|
65
|
+
const kebabDir = path.basename(compdir);
|
|
66
|
+
const skillHit = skills.has(kebabDir) || vueNames.some((v) => skills.has(v));
|
|
67
|
+
const snippetHit = snippets.some((s) => s.includes(kebabDir) || vueNames.some((v) => s.includes(v)));
|
|
68
|
+
let privCount = 0;
|
|
69
|
+
for (const f of files) {
|
|
70
|
+
const content = fs.readFileSync(f, "utf-8");
|
|
71
|
+
const m = content.match(/--_[\w-]+/g);
|
|
72
|
+
privCount += m ? new Set(m).size : 0;
|
|
73
|
+
}
|
|
74
|
+
const hasVariants = files.some((f) => path.basename(path.dirname(f)) === "variants");
|
|
75
|
+
// Legacy options-style props: `defineProps({ ... })` rather than `defineProps<Props>(...)`.
|
|
76
|
+
// A plain regex on `defineProps<` is enough to clear a file — anything calling defineProps
|
|
77
|
+
// without that generic is assumed options-style.
|
|
78
|
+
const hasLegacyProps = files.some((f) => {
|
|
79
|
+
const content = fs.readFileSync(f, "utf-8");
|
|
80
|
+
return /defineProps\s*\(/.test(content) && !/defineProps\s*<.+?>\s*\(/s.test(content);
|
|
81
|
+
});
|
|
82
|
+
rows.push({
|
|
83
|
+
compdir: relDir,
|
|
84
|
+
tier,
|
|
85
|
+
n_vue: files.length,
|
|
86
|
+
variants: hasVariants,
|
|
87
|
+
legacy_props: hasLegacyProps,
|
|
88
|
+
consumer_styling: hasConsumerStyling,
|
|
89
|
+
tests: hasTests,
|
|
90
|
+
stories: hasStoriesDir || hasStoriesFile,
|
|
91
|
+
skill: skillHit,
|
|
92
|
+
snippet: snippetHit,
|
|
93
|
+
priv_tokens: privCount,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
rows.forEach((d) => {
|
|
98
|
+
d.score = ["consumer_styling", "tests", "stories", "skill", "snippet"].filter((k) => d[k]).length;
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const auditedAt = new Date().toISOString().slice(0, 10);
|
|
102
|
+
const payload = { auditedAt, rows };
|
|
103
|
+
|
|
104
|
+
fs.writeFileSync(path.join(here, "audit.json"), JSON.stringify(payload));
|
|
105
|
+
|
|
106
|
+
const template = fs.readFileSync(path.join(here, "template.html"), "utf-8");
|
|
107
|
+
const output = template.replace("__PAYLOAD__", JSON.stringify(payload));
|
|
108
|
+
fs.writeFileSync(path.join(here, "output.html"), output);
|
|
109
|
+
|
|
110
|
+
console.log(`Component Ledger rebuilt: ${rows.length} groups, ${rows.reduce((s, d) => s + d.n_vue, 0)} .vue files.`);
|
|
111
|
+
console.log(`Output: ${path.join(here, "output.html")}`);
|