dslinter 0.1.5 → 0.2.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/CHANGELOG.md +112 -0
- package/README.md +54 -27
- package/bin/dslinter.mjs +26 -5
- package/bin/lib/config-hide-component.mjs +44 -0
- package/bin/lib/config-hide-component.test.mjs +33 -0
- package/bin/lib/constants.mjs +20 -0
- package/bin/lib/dev-banner.mjs +16 -51
- package/bin/lib/dev-banner.test.mjs +20 -18
- package/bin/lib/enrich-playgrounds-from-ts.mjs +201 -0
- package/bin/lib/enrich-playgrounds-from-ts.test.mjs +74 -0
- package/bin/lib/enrich-report-cli.mjs +14 -0
- package/bin/lib/env.mjs +20 -0
- package/bin/lib/infer-prop-types-from-ts.mjs +381 -0
- package/bin/lib/infer-prop-types-from-ts.test.mjs +174 -0
- package/bin/lib/parse-args.mjs +13 -1
- package/bin/lib/parse-args.test.mjs +7 -1
- package/bin/lib/paths.mjs +8 -0
- package/bin/lib/project-root.mjs +92 -24
- package/bin/lib/project-root.test.mjs +52 -0
- package/bin/lib/prompt.mjs +31 -0
- package/bin/lib/resolve-project.mjs +78 -0
- package/bin/lib/resolve-project.test.mjs +74 -0
- package/bin/lib/run-scanner.mjs +40 -6
- package/bin/lib/scaffold-config.mjs +163 -0
- package/bin/lib/scaffold-config.test.mjs +43 -0
- package/bin/lib/scan-host.mjs +44 -0
- package/bin/lib/scan-host.test.mjs +41 -0
- package/bin/lib/setup-readiness.mjs +153 -0
- package/bin/lib/setup-readiness.test.mjs +32 -0
- package/bin/modes/build.mjs +31 -6
- package/bin/modes/dev.mjs +56 -13
- package/bin/modes/init.mjs +35 -47
- package/bin/modes/init.test.mjs +16 -0
- package/bin/modes/mcp.mjs +49 -0
- package/bin/modes/report.mjs +29 -4
- package/bin/modes/watch.mjs +85 -0
- package/dashboard-dist/assets/DashboardLayoutAuto-Bja3BuZZ.css +1 -0
- package/dashboard-dist/assets/DashboardLayoutAuto-h0gP_iKd.js +1 -0
- package/dashboard-dist/assets/axe-DDaE9JTN.js +20 -0
- package/dashboard-dist/assets/index-B9sZ6wHm.css +1 -0
- package/dashboard-dist/assets/index-DIDBt5ed.js +218 -0
- package/dashboard-dist/index.html +2 -2
- package/index.cjs +53 -52
- package/index.d.ts +3 -0
- package/package.json +18 -12
- package/shared/env.ts +15 -0
- package/shared/paths.ts +8 -0
- package/shared/reportPath.test.ts +19 -0
- package/shared/reportPath.ts +12 -0
- package/shared/servePort.ts +16 -0
- package/src/components/ComponentInspectPane.tsx +67 -19
- package/src/components/ComponentPlaygroundPane.tsx +262 -113
- package/src/components/DashboardCommandPalette.tsx +6 -11
- package/src/components/GovernancePane.tsx +2 -2
- package/src/components/HideFromCatalogButton.tsx +44 -0
- package/src/components/OpenInEditorButton.tsx +36 -0
- package/src/components/PlaygroundA11yAndCode.tsx +53 -53
- package/src/components/PlaygroundAppThemeWrapper.tsx +82 -0
- package/src/components/PlaygroundControls.tsx +5 -11
- package/src/components/PlaygroundPreviewErrorBoundary.tsx +54 -0
- package/src/components/PlaygroundUsageCode.tsx +6 -4
- package/src/components/PlaygroundVariantMatrix.tsx +101 -34
- package/src/components/Section.tsx +5 -2
- package/src/components/Sidebar.tsx +131 -46
- package/src/components/TruncatedPath.tsx +44 -0
- package/src/components/controlApiTable.test.ts +29 -0
- package/src/components/controlApiTable.ts +3 -0
- package/src/components/playgroundUsageHighlight.ts +14 -3
- package/src/components/ui/badge.tsx +1 -1
- package/src/components/ui/table.tsx +2 -2
- package/src/dashboard/ComponentCatalog.tsx +16 -23
- package/src/dashboard/ComponentUsageDetails.tsx +6 -15
- package/src/dashboard/DashboardBody.tsx +0 -35
- package/src/dashboard/FindingsList.tsx +65 -55
- package/src/dashboard/ScannedTokenWall.tsx +3 -3
- package/src/dashboard/aggregate.test.ts +74 -0
- package/src/dashboard/aggregate.ts +145 -21
- package/src/dashboard/catalogVisibility.test.ts +93 -0
- package/src/dashboard/catalogVisibility.ts +108 -0
- package/src/dashboard/editorLink.test.ts +57 -0
- package/src/dashboard/editorLink.ts +71 -0
- package/src/dashboard/paths.test.ts +49 -0
- package/src/dashboard/paths.ts +51 -3
- package/src/dashboard/updateDslintConfig.ts +22 -0
- package/src/dashboard/useWorkspaceReport.ts +21 -17
- package/src/index.ts +26 -0
- package/src/mcp/agent-context.ts +148 -0
- package/src/mcp/agent-query.test.ts +89 -0
- package/src/mcp/agent-query.ts +373 -0
- package/src/mcp/config.ts +53 -0
- package/src/mcp/index.ts +18 -0
- package/src/mcp/normalize-paths.ts +65 -0
- package/src/mcp/report-cache.ts +209 -0
- package/src/mcp/rule-catalog.json +156 -0
- package/src/mcp/rule-catalog.ts +33 -0
- package/src/mcp/schemas.ts +54 -0
- package/src/mcp/server.test.ts +44 -0
- package/src/mcp/server.ts +343 -0
- package/src/mcp/start.ts +29 -0
- package/src/mcp/verify-loop.test.ts +49 -0
- package/src/mcp/verify-loop.ts +149 -0
- package/src/playground/appPreviewTheme.test.ts +148 -0
- package/src/playground/appPreviewTheme.ts +137 -0
- package/src/playground/buildCompoundPlaygroundEntries.test.ts +348 -0
- package/src/playground/buildCompoundPlaygroundEntries.ts +625 -0
- package/src/playground/buildPlaygroundEntriesFromReport.test.ts +420 -6
- package/src/playground/buildPlaygroundEntriesFromReport.ts +206 -285
- package/src/playground/catalogIdFromPlaygroundExport.test.ts +15 -0
- package/src/playground/catalogIdFromPlaygroundExport.ts +8 -0
- package/src/playground/collectDefinedPlaygrounds.test.ts +59 -0
- package/src/playground/collectDefinedPlaygrounds.ts +68 -0
- package/src/playground/controls.ts +177 -0
- package/src/playground/createPlaygroundRegistry.ts +1 -1
- package/src/playground/definePlayground.tsx +88 -16
- package/src/playground/definePlaygroundFromKit.ts +17 -0
- package/src/playground/embedGlobKey.ts +8 -0
- package/src/playground/enrichKitControls.test.ts +25 -0
- package/src/playground/enrichKitControls.ts +197 -0
- package/src/playground/expandPlaygroundControls.test.ts +50 -0
- package/src/playground/expandPlaygroundControls.ts +97 -0
- package/src/playground/inferKitJsx.test.ts +77 -0
- package/src/playground/inferKitJsx.ts +165 -0
- package/src/playground/inferKitParams.test.ts +41 -0
- package/src/playground/inferKitParams.ts +113 -0
- package/src/playground/inferPropTypesFromTs.d.mts +47 -0
- package/src/playground/inferPropTypesFromTs.mjs +343 -0
- package/src/playground/inferPropTypesFromTs.test.ts +227 -0
- package/src/playground/inferPropTypesFromTs.ts +17 -0
- package/src/playground/mergePlaygroundEntries.test.ts +32 -0
- package/src/playground/mergePlaygroundEntries.ts +28 -0
- package/src/playground/playgroundJoin.test.ts +79 -19
- package/src/playground/playgroundJoin.ts +47 -22
- package/src/playground/playgroundModuleExport.test.ts +42 -0
- package/src/playground/playgroundModuleExport.ts +22 -0
- package/src/playground/playgroundSpecsKey.ts +8 -0
- package/src/playground/propCoerce.ts +91 -0
- package/src/playground/scanVariantA11y.test.ts +46 -0
- package/src/playground/scanVariantA11y.ts +107 -0
- package/src/playground/snippet.ts +83 -0
- package/src/playground/usePlaygroundFromReport.test.ts +18 -8
- package/src/playground/usePlaygroundFromReport.ts +3 -1
- package/src/report/a11yForModule.ts +2 -7
- package/src/report/a11yScoring.test.ts +24 -0
- package/src/report/a11yScoring.ts +17 -0
- package/src/report/index.ts +6 -0
- package/src/shell/DashboardLayout.tsx +71 -45
- package/src/shell/DashboardLayoutAuto.tsx +0 -4
- package/src/shell/hashRoute.test.ts +7 -15
- package/src/shell/hashRoute.ts +31 -31
- package/src/shell/useHashRoute.ts +38 -13
- package/src/styles/dashboard-theme.css +18 -7
- package/src/types/controls.ts +11 -0
- package/src/types/playground.ts +4 -0
- package/src/types/report.ts +32 -9
- package/templates/playground/buildRegistry.ts +1 -1
- package/templates/vite.dslinter.snippet.ts +15 -4
- package/vite/collectScanModules.test.ts +51 -3
- package/vite/collectScanModules.ts +85 -29
- package/vite/consumer.config.mjs +6 -3
- package/vite/consumerAlias.test.ts +47 -0
- package/vite/consumerAlias.ts +114 -0
- package/vite/embedTailwindSources.test.ts +74 -0
- package/vite/embedTailwindSources.ts +97 -0
- package/vite/loadConsumerAliases.test.ts +131 -0
- package/vite/loadConsumerAliases.ts +155 -0
- package/vite/openFileInEditor.mjs +196 -0
- package/vite/openFileInEditor.test.mjs +87 -0
- package/vite/plugin.resolve.test.ts +72 -0
- package/vite/plugin.ts +216 -19
- package/vite/reportPath.test.ts +19 -0
- package/vite/resolveWayfinderImport.ts +56 -0
- package/vite/shims/inertia-react.tsx +85 -0
- package/vite/shims/wayfinder-actions.ts +33 -0
- package/vite/shims/wayfinder-routes.ts +30 -0
- package/vite/shims/ziggy-js.ts +12 -0
- package/dashboard-dist/assets/DashboardLayoutAuto-BPPtPsYh.css +0 -1
- package/dashboard-dist/assets/DashboardLayoutAuto-Dp3bAQxH.js +0 -1
- package/dashboard-dist/assets/index-DsjwnDdX.js +0 -206
- package/dashboard-dist/assets/index-jaCmZJlW.css +0 -1
- package/src/components/playgroundUsageTwoslash.ts +0 -69
- package/templates/vite.dslint-scan-alias.snippet.ts +0 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,117 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.2.0
|
|
4
|
+
|
|
5
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.1.13...v0.2.0)
|
|
6
|
+
|
|
7
|
+
### 🚀 Enhancements
|
|
8
|
+
|
|
9
|
+
- **website:** Switch deploy config from pages to workers ([22d7e35](https://github.com/jrmybtlr/DSLinter/commit/22d7e35))
|
|
10
|
+
- **playground:** Add user info playground component and enhance controls handling ([625f7c2](https://github.com/jrmybtlr/DSLinter/commit/625f7c2))
|
|
11
|
+
|
|
12
|
+
### 🔥 Performance
|
|
13
|
+
|
|
14
|
+
- Precompute newline_offsets once in analyze_vue_file, pass to merge_template_usages ([a2839b3](https://github.com/jrmybtlr/DSLinter/commit/a2839b3))
|
|
15
|
+
|
|
16
|
+
### 🩹 Fixes
|
|
17
|
+
|
|
18
|
+
- **dashboard:** Address PR review feedback on publish files and API export ([d3a1f1b](https://github.com/jrmybtlr/DSLinter/commit/d3a1f1b))
|
|
19
|
+
- Import website main stylesheet in entrypoint ([79fa1ec](https://github.com/jrmybtlr/DSLinter/commit/79fa1ec))
|
|
20
|
+
- Remove duplicate typescript devDependency in dashboard package ([03e3dc1](https://github.com/jrmybtlr/DSLinter/commit/03e3dc1))
|
|
21
|
+
- Address review comments - remove duplicate typescript dep, add .d.mts declaration, remove dead code ([cbfd7ab](https://github.com/jrmybtlr/DSLinter/commit/cbfd7ab))
|
|
22
|
+
|
|
23
|
+
### 💅 Refactors
|
|
24
|
+
|
|
25
|
+
- **rust:** Consolidate usage maps, DRY FileScan ctors, remove scan_and_evaluate, fix scoring bugs, use lazy_regex! ([5033b13](https://github.com/jrmybtlr/DSLinter/commit/5033b13))
|
|
26
|
+
- **ts:** Split playground module, useRef cancellation, Set dedup, useMemo fixes, DashboardLayout, Sidebar, barrel index ([d57a673](https://github.com/jrmybtlr/DSLinter/commit/d57a673))
|
|
27
|
+
|
|
28
|
+
### 📖 Documentation
|
|
29
|
+
|
|
30
|
+
- Update README config options ([5f2be14](https://github.com/jrmybtlr/DSLinter/commit/5f2be14))
|
|
31
|
+
- Remove trailing spaces in README ([1fc4c1d](https://github.com/jrmybtlr/DSLinter/commit/1fc4c1d))
|
|
32
|
+
|
|
33
|
+
### 🏡 Chore
|
|
34
|
+
|
|
35
|
+
- **release:** V0.1.13 ([3cd1a20](https://github.com/jrmybtlr/DSLinter/commit/3cd1a20))
|
|
36
|
+
- **dashboard:** Remove dead code and dedupe helpers ([cb41bcd](https://github.com/jrmybtlr/DSLinter/commit/cb41bcd))
|
|
37
|
+
- Begin optimisation pass over src/ and packages/dashboard ([8ec1a34](https://github.com/jrmybtlr/DSLinter/commit/8ec1a34))
|
|
38
|
+
- Plan cloudflare workers website deploy ([affabf5](https://github.com/jrmybtlr/DSLinter/commit/affabf5))
|
|
39
|
+
- Add semver as a dev dependency and update pnpm lockfile ([18afb12](https://github.com/jrmybtlr/DSLinter/commit/18afb12))
|
|
40
|
+
|
|
41
|
+
### ❤️ Contributors
|
|
42
|
+
|
|
43
|
+
- Jeremy Butler <jeremy.butler@laravel.com>
|
|
44
|
+
- Cursor Agent ([@cursoragent](https://github.com/cursoragent))
|
|
45
|
+
|
|
46
|
+
## v0.1.13
|
|
47
|
+
|
|
48
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.1.12...v0.1.13)
|
|
49
|
+
|
|
50
|
+
### 🏡 Chore
|
|
51
|
+
|
|
52
|
+
- **release:** V0.1.12 ([7c2190a](https://github.com/jrmybtlr/DSLinter/commit/7c2190a))
|
|
53
|
+
|
|
54
|
+
### ❤️ Contributors
|
|
55
|
+
|
|
56
|
+
- Jeremy Butler <jeremy.butler@laravel.com>
|
|
57
|
+
|
|
58
|
+
## v0.1.12
|
|
59
|
+
|
|
60
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.1.10...v0.1.12)
|
|
61
|
+
|
|
62
|
+
### 🏡 Chore
|
|
63
|
+
|
|
64
|
+
- **release:** V0.1.11 ([bc2d134](https://github.com/jrmybtlr/DSLinter/commit/bc2d134))
|
|
65
|
+
|
|
66
|
+
### ❤️ Contributors
|
|
67
|
+
|
|
68
|
+
- Jeremy Butler <jeremy.butler@laravel.com>
|
|
69
|
+
|
|
70
|
+
## v0.1.11
|
|
71
|
+
|
|
72
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.1.10...v0.1.11)
|
|
73
|
+
|
|
74
|
+
## v0.1.10
|
|
75
|
+
|
|
76
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.1.8...v0.1.10)
|
|
77
|
+
|
|
78
|
+
### 🏡 Chore
|
|
79
|
+
|
|
80
|
+
- **release:** V0.1.9 ([a54ea04](https://github.com/jrmybtlr/DSLinter/commit/a54ea04))
|
|
81
|
+
|
|
82
|
+
### ❤️ Contributors
|
|
83
|
+
|
|
84
|
+
- Jeremy Butler <jeremy.butler@laravel.com>
|
|
85
|
+
|
|
86
|
+
## v0.1.8
|
|
87
|
+
|
|
88
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.1.7...v0.1.8)
|
|
89
|
+
|
|
90
|
+
### 🚀 Enhancements
|
|
91
|
+
|
|
92
|
+
- Auto-scaffold dslint config and add scan scope options ([572e97b](https://github.com/jrmybtlr/DSLinter/commit/572e97b))
|
|
93
|
+
|
|
94
|
+
### 🩹 Fixes
|
|
95
|
+
|
|
96
|
+
- Warn when css_entrypoint path is missing ([88a5038](https://github.com/jrmybtlr/DSLinter/commit/88a5038))
|
|
97
|
+
- Don't scope CSS discovery to include_dirs ([7e6df94](https://github.com/jrmybtlr/DSLinter/commit/7e6df94))
|
|
98
|
+
|
|
99
|
+
## v0.1.7
|
|
100
|
+
|
|
101
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.1.5...v0.1.7)
|
|
102
|
+
|
|
103
|
+
### 🏡 Chore
|
|
104
|
+
|
|
105
|
+
- **release:** V0.1.6 ([1463fbc](https://github.com/jrmybtlr/DSLinter/commit/1463fbc))
|
|
106
|
+
|
|
107
|
+
### ❤️ Contributors
|
|
108
|
+
|
|
109
|
+
- Jeremy Butler <jeremy.butler@laravel.com>
|
|
110
|
+
|
|
111
|
+
## v0.1.6
|
|
112
|
+
|
|
113
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.1.5...v0.1.6)
|
|
114
|
+
|
|
3
115
|
## v0.1.5
|
|
4
116
|
|
|
5
117
|
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.1.4...v0.1.5)
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# dslinter
|
|
2
2
|
|
|
3
|
-
React UI for the **DSLinter dashboard**: component playground shell, token wall, and governance panels. It expects a **`
|
|
3
|
+
React UI for the **DSLinter dashboard**: component playground shell, token wall, and governance panels. It expects a **`dslinter-report.json`** file produced by the **`dslinter`** CLI (Rust scanner powered by [Oxc](https://oxc.rs) in this repo).
|
|
4
4
|
|
|
5
5
|
**Previously published as `@dslinter/dashboard`.** Migrate with `npm install dslinter` and replace imports `@dslinter/dashboard` → `dslinter`, and `@dslinter/dashboard/theme.css` → `dslinter/theme.css`.
|
|
6
6
|
|
|
@@ -24,9 +24,10 @@ The **`dslinter`** command orchestrates the Rust scanner (via **napi-rs**, same
|
|
|
24
24
|
| Mode | Flag | Behavior |
|
|
25
25
|
|------|------|----------|
|
|
26
26
|
| Dev (default locally) | _(none)_ | `--serve`, watch, write `--output`, start Vite `--mode serve` |
|
|
27
|
-
| Report | `--report` | One-shot scan; human stdout or `--json`; `--output` writes JSON |
|
|
28
|
-
| Watch | `--watch` | Watch + write JSON only |
|
|
29
|
-
| Build | `--build` | One-shot report to `--output
|
|
27
|
+
| Report | `--report` | One-shot scan; human stdout or `--json`; `--output` writes JSON; enriches playground prop kinds/options from TypeScript when `tsconfig.json` is present |
|
|
28
|
+
| Watch | `--watch` | Watch + write JSON only; re-enriches playgrounds after each scan |
|
|
29
|
+
| Build | `--build` | One-shot report to `--output` (with TS enrichment), then `vite build` |
|
|
30
|
+
| MCP | `mcp` | Stdio MCP server for AI agents (catalog, findings, agent context) |
|
|
30
31
|
| CI default | `CI=true` | Same as `--report` |
|
|
31
32
|
|
|
32
33
|
Scanner flags: `--json`, `-p` / `--parallel`, `--fail-on-warnings`, `--max-warnings`, `--output`, `[PATH]`. Low-level: `--serve <port>` (watch + HTTP, no Vite).
|
|
@@ -37,42 +38,48 @@ On **`npm install dslinter`**, npm installs the platform **`@dslinter/binding-*`
|
|
|
37
38
|
|
|
38
39
|
| Variable | Purpose |
|
|
39
40
|
|----------|---------|
|
|
40
|
-
| `
|
|
41
|
-
| `
|
|
41
|
+
| `DSLINTER_BIN` | Use a cargo-built `dslinter` binary instead of the NAPI binding. |
|
|
42
|
+
| `DSLINTER_ALLOW_PATH=1` | Allow `dslinter` on `PATH` when the binding is missing. |
|
|
42
43
|
| `NAPI_RS_NATIVE_LIBRARY_PATH` | Point at a specific `.node` file (napi-rs escape hatch). |
|
|
43
44
|
|
|
44
45
|
### Do not `cargo install dslint`
|
|
45
46
|
|
|
46
|
-
The crates.io crate **`dslint`** is a **different project**. Use **`cargo install --git https://github.com/jrmybtlr/DSLinter dslinter --locked`** or **`
|
|
47
|
+
The crates.io crate **`dslint`** is a **different project**. Use **`cargo install --git https://github.com/jrmybtlr/DSLinter dslinter --locked`** or **`DSLINTER_BIN`** for local Rust builds.
|
|
47
48
|
|
|
48
49
|
Typical usage:
|
|
49
50
|
|
|
50
51
|
```bash
|
|
51
|
-
npx dslinter
|
|
52
|
-
npx dslinter
|
|
53
|
-
npx dslinter
|
|
54
|
-
npx dslinter --report --
|
|
55
|
-
npx dslinter --
|
|
52
|
+
npx dslinter # dev (watch + dashboard) — run from any project subdirectory
|
|
53
|
+
npx dslinter --yes # dev + auto-create .dslinter.json and public/ without prompting
|
|
54
|
+
npx dslinter init # optional: scaffold buildRegistry.ts for custom controls
|
|
55
|
+
npx dslinter --report demo --json
|
|
56
|
+
npx dslinter --report --output public/dslinter-report.json
|
|
57
|
+
npx dslinter --watch --output public/dslinter-report.json
|
|
56
58
|
```
|
|
57
59
|
|
|
58
|
-
Set `
|
|
60
|
+
Set `DSLINTER_SERVE_PORT` to override the default scanner port (`7878`).
|
|
61
|
+
When dev mode prints both a **Dashboard** URL and a **Scanner API** URL, open the **Dashboard** URL for the UI (port 7878 is the scanner API only).
|
|
62
|
+
|
|
63
|
+
On first local run in an interactive terminal, `npx dslinter` asks whether to create minimal setup files (`.dslinter.json` and `public/`). In CI or with `--yes`, those files are created automatically. Set `DSLINTER_NO_SCAFFOLD=1` to skip all writes.
|
|
64
|
+
|
|
65
|
+
| Flag / variable | Purpose |
|
|
66
|
+
|-----------------|--------|
|
|
67
|
+
| `--yes` / `-y` | Create minimal scaffold without prompting |
|
|
68
|
+
| `DSLINTER_NO_SCAFFOLD=1` | Never write scaffold files |
|
|
69
|
+
| `DSLINTER_USE_CONSUMER_VITE=1` | Use your app's Vite dev server as the dashboard UI (embedded `<DashboardLayout />`) |
|
|
70
|
+
| `DSLINTER_NO_EMBED_VITE=1` | Disable standalone embed dashboard dev server |
|
|
59
71
|
|
|
60
72
|
### Zero-config live previews (recommended)
|
|
61
73
|
|
|
62
|
-
**`npx dslinter
|
|
74
|
+
Run **`npx dslinter`** from your repo (including `resources/js/Components` or other subdirectories — the CLI resolves the project root automatically). For **Laravel / Inertia** apps, dev mode starts a **standalone DSLinter dashboard** with live previews; you do **not** need to add `<DashboardLayout />` to your Inertia app.
|
|
63
75
|
|
|
64
|
-
|
|
65
|
-
import { DashboardLayout, useWorkspaceReport } from "dslinter";
|
|
76
|
+
Previews load your components with your Vite `@/` aliases and Inertia stubs (`usePage`, `<Link>`, etc.) so isolated components render without a full page visit.
|
|
66
77
|
|
|
67
|
-
|
|
68
|
-
reportUrl: "/dslint-report.json",
|
|
69
|
-
watchUrl: "/events",
|
|
70
|
-
});
|
|
78
|
+
The embed dev server registers Tailwind `@source` paths for your `.dslinter.json` **`include_dirs`** (for example `resources/js/components`), so component utility classes like `px-3.5` are generated in preview CSS. For 100% parity with your app's full CSS pipeline (theme entry, `@custom-variant`, etc.), use `DSLINTER_USE_CONSUMER_VITE=1` instead.
|
|
71
79
|
|
|
72
|
-
|
|
73
|
-
```
|
|
80
|
+
The prebuilt **`dashboard-dist`** bundle shipped on npm does not run this Vite transform; use embed dev mode (monorepo / git checkout) or consumer Vite for accurate preview styling.
|
|
74
81
|
|
|
75
|
-
|
|
82
|
+
For apps that already embed the dashboard (like this repo's `demo/`), dev mode uses your app's Vite server when `src/App.tsx` imports `DashboardLayout` from `dslinter`.
|
|
76
83
|
|
|
77
84
|
**Direct `vite --mode serve`:** add one line to `vite.config.ts`:
|
|
78
85
|
|
|
@@ -84,12 +91,27 @@ export default defineConfig({
|
|
|
84
91
|
});
|
|
85
92
|
```
|
|
86
93
|
|
|
87
|
-
The plugin sets `
|
|
94
|
+
The plugin sets `DSLINTER_SCAN_ROOT` from the environment (set by `npx dslinter`) or defaults to `process.cwd()`.
|
|
88
95
|
|
|
89
96
|
### Consumer Vite (Laravel, Inertia, existing `@/*` aliases)
|
|
90
97
|
|
|
91
98
|
Published `dslinter` source uses **relative imports only** — your app's `@/*` alias does not hijack dslinter internal UI. You do **not** need `@/components` → `node_modules/dslinter` alias overrides.
|
|
92
99
|
|
|
100
|
+
### Laravel / Inertia (zero app code)
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
cd my-laravel-app
|
|
104
|
+
npx dslinter
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Open the **Dashboard** URL from the terminal banner (default port `5175`). The scanner writes `public/dslinter-report.json` at the project root.
|
|
108
|
+
|
|
109
|
+
No Inertia route, no `buildRegistry.ts`, and no `vite.config` edits are required for dev previews.
|
|
110
|
+
|
|
111
|
+
**Optional — embed dashboard in your app:** set `DSLINTER_USE_CONSUMER_VITE=1`, add `plugins: [dslinter()]` from `dslinter/vite`, and render `<DashboardLayout autoPlayground dslinterReport={...} />`.
|
|
112
|
+
|
|
113
|
+
**Optional — custom playground controls:** `npx dslinter init --laravel` scaffolds `resources/js/playground/buildRegistry.ts`.
|
|
114
|
+
|
|
93
115
|
## Styles (Tailwind v4)
|
|
94
116
|
|
|
95
117
|
1. In your app CSS, load Tailwind, then point Tailwind at this package so utility scanning picks up dashboard classes:
|
|
@@ -112,12 +134,17 @@ Use **`autoPlayground`** (above) for zero-config previews. Optionally scaffold a
|
|
|
112
134
|
- `npx dslinter init` → `src/playground/buildRegistry.ts`
|
|
113
135
|
- `npx dslinter init --laravel` → `resources/js/playground/buildRegistry.ts`
|
|
114
136
|
|
|
137
|
+
`npx dslinter init` now also scaffolds a starter `.dslinter.json` (unless one already exists), including:
|
|
138
|
+
- `include_dirs` (directory scope for discovery)
|
|
139
|
+
- `ignore_globs` (file/directory ignores)
|
|
140
|
+
- `css_entrypoints` (main CSS entry files for token analysis)
|
|
141
|
+
|
|
115
142
|
```tsx
|
|
116
143
|
import { useMemo } from "react";
|
|
117
144
|
import { DashboardLayout, useWorkspaceReport } from "dslinter";
|
|
118
145
|
import { buildPlaygroundEntries } from "./playground/buildRegistry";
|
|
119
146
|
|
|
120
|
-
const dslinterReport = useWorkspaceReport({ reportUrl: "/
|
|
147
|
+
const dslinterReport = useWorkspaceReport({ reportUrl: "/dslinter-report.json", watchUrl: "/events" });
|
|
121
148
|
const playgroundEntries = useMemo(
|
|
122
149
|
() => buildPlaygroundEntries(dslinterReport.report),
|
|
123
150
|
[dslinterReport.report],
|
|
@@ -137,7 +164,7 @@ Run the scanner from the **project root** (`npx dslinter .`) so `playgrounds[].r
|
|
|
137
164
|
- **`autoPlayground`** (recommended) — or **`playgroundEntries`** from a custom registry / `usePlaygroundFromReport`.
|
|
138
165
|
- **`playgroundJoinSkips`** (optional) — auto-filled when using `autoPlayground`.
|
|
139
166
|
- **`tokenCatalog`** — token wall data (see `demo/src/tokenCatalog.ts`).
|
|
140
|
-
- **`dslinterReport`** — from `useWorkspaceReport({ reportUrl: "/
|
|
167
|
+
- **`dslinterReport`** — from `useWorkspaceReport({ reportUrl: "/dslinter-report.json", ... })`.
|
|
141
168
|
|
|
142
169
|
```tsx
|
|
143
170
|
import { useMemo } from "react";
|
|
@@ -150,7 +177,7 @@ import { tokenCatalog } from "./tokenCatalog";
|
|
|
150
177
|
|
|
151
178
|
export default function App() {
|
|
152
179
|
const dslinterReport = useWorkspaceReport({
|
|
153
|
-
reportUrl: "/
|
|
180
|
+
reportUrl: "/dslinter-report.json",
|
|
154
181
|
refreshIntervalMs: 5000,
|
|
155
182
|
});
|
|
156
183
|
|
package/bin/dslinter.mjs
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* DSLinter CLI: mode routing (dev / report / watch / build) + scanner (NAPI or
|
|
3
|
+
* DSLinter CLI: mode routing (dev / report / watch / build) + scanner (NAPI or DSLINTER_BIN).
|
|
4
4
|
*/
|
|
5
5
|
import { parseDslinterArgs } from "./lib/parse-args.mjs";
|
|
6
|
+
import { withScannerScanPath } from "./lib/resolve-project.mjs";
|
|
7
|
+
import { logScanScopeHint } from "./lib/project-root.mjs";
|
|
6
8
|
import { runScannerInternal } from "./lib/run-scanner.mjs";
|
|
7
9
|
import { runBuildMode } from "./modes/build.mjs";
|
|
8
10
|
import { runDevMode } from "./modes/dev.mjs";
|
|
9
11
|
import { runInitMode } from "./modes/init.mjs";
|
|
12
|
+
import { runMcpMode } from "./modes/mcp.mjs";
|
|
10
13
|
import { runReportMode } from "./modes/report.mjs";
|
|
11
14
|
|
|
12
15
|
const rawArgs = process.argv.slice(2);
|
|
@@ -16,6 +19,10 @@ if (rawArgs[0] === "init") {
|
|
|
16
19
|
process.exit(0);
|
|
17
20
|
}
|
|
18
21
|
|
|
22
|
+
if (rawArgs[0] === "mcp") {
|
|
23
|
+
await runMcpMode({ argv: rawArgs.slice(1) });
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
if (process.env.DSLINTER_INTERNAL === "1") {
|
|
20
27
|
runScannerInternal(rawArgs);
|
|
21
28
|
}
|
|
@@ -36,23 +43,37 @@ try {
|
|
|
36
43
|
process.exit(1);
|
|
37
44
|
}
|
|
38
45
|
|
|
39
|
-
const { mode
|
|
46
|
+
const { mode } = parsed;
|
|
47
|
+
logScanScopeHint({
|
|
48
|
+
scanPath: parsed.scanPath,
|
|
49
|
+
projectRoot: parsed.projectRoot,
|
|
50
|
+
explicitScanPath: parsed.explicitScanPath,
|
|
51
|
+
});
|
|
52
|
+
const scannerArgs = withScannerScanPath(parsed.scannerArgs, parsed.scanPath);
|
|
53
|
+
const runParsed = { ...parsed, scannerArgs };
|
|
40
54
|
|
|
41
55
|
switch (mode) {
|
|
42
56
|
case "dev":
|
|
43
|
-
await runDevMode(
|
|
57
|
+
await runDevMode(runParsed);
|
|
44
58
|
break;
|
|
45
59
|
case "report":
|
|
46
|
-
runReportMode(
|
|
60
|
+
await runReportMode({
|
|
61
|
+
scanPath: runParsed.scanPath,
|
|
62
|
+
projectRoot: runParsed.projectRoot,
|
|
63
|
+
outputPath: runParsed.outputPath,
|
|
64
|
+
scannerArgs: runParsed.scannerArgs,
|
|
65
|
+
});
|
|
47
66
|
break;
|
|
48
67
|
case "watch":
|
|
68
|
+
process.env.DSLINTER_PROJECT_ROOT = runParsed.projectRoot;
|
|
49
69
|
runScannerInternal(["--watch", ...scannerArgs]);
|
|
50
70
|
break;
|
|
51
71
|
case "scanner":
|
|
72
|
+
process.env.DSLINTER_PROJECT_ROOT = runParsed.projectRoot;
|
|
52
73
|
runScannerInternal(scannerArgs);
|
|
53
74
|
break;
|
|
54
75
|
case "build":
|
|
55
|
-
runBuildMode(
|
|
76
|
+
await runBuildMode(runParsed);
|
|
56
77
|
break;
|
|
57
78
|
default:
|
|
58
79
|
process.stderr.write(`dslinter: unknown mode ${mode}\n`);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const CONFIG_FILE_NAMES = [".dslinter.json", "dslinter.json"];
|
|
4
|
+
const DEFAULT_CONFIG_FILE_NAME = ".dslinter.json";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} projectRoot
|
|
8
|
+
* @returns {string}
|
|
9
|
+
*/
|
|
10
|
+
export function findDslintConfigPath(projectRoot) {
|
|
11
|
+
for (const name of CONFIG_FILE_NAMES) {
|
|
12
|
+
const candidate = join(projectRoot, name);
|
|
13
|
+
if (existsSync(candidate)) return candidate;
|
|
14
|
+
}
|
|
15
|
+
return join(projectRoot, DEFAULT_CONFIG_FILE_NAME);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} projectRoot
|
|
20
|
+
* @param {string} componentName
|
|
21
|
+
* @returns {{ hidden_components: string[] }}
|
|
22
|
+
*/
|
|
23
|
+
export function hideComponentInDslintConfig(projectRoot, componentName) {
|
|
24
|
+
const name = String(componentName ?? "").trim();
|
|
25
|
+
if (!name) {
|
|
26
|
+
throw new Error("component name is required");
|
|
27
|
+
}
|
|
28
|
+
const configPath = findDslintConfigPath(projectRoot);
|
|
29
|
+
let config = {};
|
|
30
|
+
if (existsSync(configPath)) {
|
|
31
|
+
try {
|
|
32
|
+
config = JSON.parse(readFileSync(configPath, "utf8"));
|
|
33
|
+
} catch (e) {
|
|
34
|
+
throw new Error(`Invalid JSON in ${configPath}: ${e.message}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const hidden = Array.isArray(config.hidden_components)
|
|
38
|
+
? [...config.hidden_components]
|
|
39
|
+
: [];
|
|
40
|
+
if (!hidden.includes(name)) hidden.push(name);
|
|
41
|
+
config.hidden_components = hidden;
|
|
42
|
+
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
43
|
+
return { hidden_components: hidden };
|
|
44
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
5
|
+
import { hideComponentInDslintConfig } from "./config-hide-component.mjs";
|
|
6
|
+
|
|
7
|
+
describe("hideComponentInDslintConfig", () => {
|
|
8
|
+
const dirs = [];
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
for (const dir of dirs) rmSync(dir, { recursive: true, force: true });
|
|
12
|
+
dirs.length = 0;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("appends hidden_components to a new config file", () => {
|
|
16
|
+
const root = mkdtempSync(join(tmpdir(), "dslint-hide-"));
|
|
17
|
+
dirs.push(root);
|
|
18
|
+
const result = hideComponentInDslintConfig(root, "Foo");
|
|
19
|
+
expect(result.hidden_components).toEqual(["Foo"]);
|
|
20
|
+
const written = JSON.parse(
|
|
21
|
+
readFileSync(join(root, ".dslinter.json"), "utf8"),
|
|
22
|
+
);
|
|
23
|
+
expect(written.hidden_components).toEqual(["Foo"]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("does not duplicate names", () => {
|
|
27
|
+
const root = mkdtempSync(join(tmpdir(), "dslint-hide-"));
|
|
28
|
+
dirs.push(root);
|
|
29
|
+
hideComponentInDslintConfig(root, "Foo");
|
|
30
|
+
const result = hideComponentInDslintConfig(root, "Foo");
|
|
31
|
+
expect(result.hidden_components).toEqual(["Foo"]);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { readEnv } from "./env.mjs";
|
|
2
|
+
|
|
3
|
+
/** @typedef {import("node:process").ProcessEnv} ProcessEnv */
|
|
4
|
+
|
|
5
|
+
/** Default scanner HTTP port when `DSLINTER_SERVE_PORT` is unset. */
|
|
6
|
+
export const DEFAULT_SERVE_PORT = 7878;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolve scanner HTTP port from `DSLINTER_SERVE_PORT` or {@link DEFAULT_SERVE_PORT}.
|
|
10
|
+
* @param {ProcessEnv} [env]
|
|
11
|
+
* @returns {number}
|
|
12
|
+
*/
|
|
13
|
+
export function resolveServePort(env = process.env) {
|
|
14
|
+
const fromEnv = readEnv("SERVE_PORT", env);
|
|
15
|
+
if (fromEnv) {
|
|
16
|
+
const n = Number.parseInt(fromEnv, 10);
|
|
17
|
+
if (Number.isFinite(n) && n > 0 && n <= 65535) return n;
|
|
18
|
+
}
|
|
19
|
+
return DEFAULT_SERVE_PORT;
|
|
20
|
+
}
|
package/bin/lib/dev-banner.mjs
CHANGED
|
@@ -172,33 +172,23 @@ export function formatDevBanner(opts) {
|
|
|
172
172
|
const maxBox = Math.min(Math.max(terminalCols, 64), 96);
|
|
173
173
|
|
|
174
174
|
const scanAbs = resolve(opts.scanPath);
|
|
175
|
-
const
|
|
176
|
-
const apiBase = `http://127.0.0.1:${opts.apiPort}`;
|
|
177
|
-
|
|
178
|
-
const apiStatusPlain = opts.apiAvailable ? "listening" : "unavailable — port in use";
|
|
179
|
-
const bundledStatusPlain = opts.apiAvailable ? "ready" : "port busy";
|
|
175
|
+
const dashboardUrl = opts.dashboardUrl ?? opts.bundledUrl ?? null;
|
|
180
176
|
const scanPlain = shortenPath(scanAbs, 80);
|
|
181
|
-
const
|
|
177
|
+
const scannerWarnPlain = opts.apiAvailable
|
|
178
|
+
? null
|
|
179
|
+
: `unavailable — port ${opts.apiPort} in use`;
|
|
182
180
|
|
|
183
181
|
/** @type {number[]} */
|
|
184
182
|
const plainWidths = [
|
|
185
183
|
...LOGO.map((l) => visibleLength(l)),
|
|
186
184
|
14 + 2 + scanPlain.length,
|
|
187
|
-
14 + 2 + reportPlain.length,
|
|
188
185
|
];
|
|
189
|
-
if (
|
|
190
|
-
if (
|
|
191
|
-
plainWidths.push(14 + 2 + `${opts.bundledUrl} (${bundledStatusPlain})`.length);
|
|
192
|
-
}
|
|
193
|
-
plainWidths.push(14 + 2 + `${apiBase} (${apiStatusPlain})`.length);
|
|
194
|
-
if (opts.apiAvailable) {
|
|
195
|
-
plainWidths.push(14 + 2 + `${apiBase}/dslint-report.json`.length);
|
|
196
|
-
plainWidths.push(14 + 2 + `${apiBase}/events`.length);
|
|
197
|
-
}
|
|
186
|
+
if (dashboardUrl) plainWidths.push(14 + 2 + dashboardUrl.length);
|
|
187
|
+
if (scannerWarnPlain) plainWidths.push(14 + 2 + scannerWarnPlain.length);
|
|
198
188
|
if (opts.pollMs) plainWidths.push(14 + 2 + `polling every ${opts.pollMs} ms`.length);
|
|
199
|
-
const footerPlain =
|
|
200
|
-
? " Open the
|
|
201
|
-
: "
|
|
189
|
+
const footerPlain = dashboardUrl
|
|
190
|
+
? " Open the Dashboard in your browser. Ctrl+C to stop."
|
|
191
|
+
: " Ctrl+C to stop.";
|
|
202
192
|
plainWidths.push(visibleLength(footerPlain));
|
|
203
193
|
|
|
204
194
|
const contentWidth = Math.min(maxBox - 4, Math.max(...plainWidths, 40));
|
|
@@ -212,45 +202,20 @@ export function formatDevBanner(opts) {
|
|
|
212
202
|
styledRows.push(
|
|
213
203
|
...row(color.label("Scan path"), scanPlain, contentWidth, color.value),
|
|
214
204
|
);
|
|
215
|
-
|
|
216
|
-
...row(color.label("Report file"), reportPlain, contentWidth, color.value),
|
|
217
|
-
);
|
|
218
|
-
styledRows.push("");
|
|
219
|
-
if (opts.dashboardUrl && !opts.bundledUrl) {
|
|
220
|
-
styledRows.push(
|
|
221
|
-
...row(color.label("Dashboard"), opts.dashboardUrl, contentWidth, color.url),
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
if (opts.bundledUrl) {
|
|
225
|
-
const status = opts.apiAvailable ? color.ok(bundledStatusPlain) : color.warn(bundledStatusPlain);
|
|
205
|
+
if (opts.pollMs) {
|
|
226
206
|
styledRows.push(
|
|
227
|
-
...row(
|
|
228
|
-
color.label("Bundled UI"),
|
|
229
|
-
`${opts.bundledUrl} (${bundledStatusPlain})`,
|
|
230
|
-
contentWidth,
|
|
231
|
-
() => `${color.url(opts.bundledUrl)} ${color.dim("(")}${status}${color.dim(")")}`,
|
|
232
|
-
),
|
|
207
|
+
...row(color.label("Watch"), `polling every ${opts.pollMs} ms`, contentWidth, color.dim),
|
|
233
208
|
);
|
|
234
209
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
...row(
|
|
238
|
-
color.label("Scanner API"),
|
|
239
|
-
`${apiBase} (${apiStatusPlain})`,
|
|
240
|
-
contentWidth,
|
|
241
|
-
() => `${color.url(apiBase)} ${color.dim("(")}${apiStatus}${color.dim(")")}`,
|
|
242
|
-
),
|
|
243
|
-
);
|
|
244
|
-
if (opts.apiAvailable) {
|
|
210
|
+
styledRows.push("");
|
|
211
|
+
if (dashboardUrl) {
|
|
245
212
|
styledRows.push(
|
|
246
|
-
...row("",
|
|
213
|
+
...row(color.label("Dashboard"), dashboardUrl, contentWidth, color.url),
|
|
247
214
|
);
|
|
248
|
-
styledRows.push(...row("", `${apiBase}/events`, contentWidth, color.dim));
|
|
249
215
|
}
|
|
250
|
-
if (
|
|
251
|
-
styledRows.push("");
|
|
216
|
+
if (scannerWarnPlain) {
|
|
252
217
|
styledRows.push(
|
|
253
|
-
...row(color.label("
|
|
218
|
+
...row(color.label("Scanner"), scannerWarnPlain, contentWidth, color.err),
|
|
254
219
|
);
|
|
255
220
|
}
|
|
256
221
|
styledRows.push("");
|
|
@@ -22,59 +22,61 @@ describe("shortenPath", () => {
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
describe("formatDevBanner", () => {
|
|
25
|
-
it("includes logo, scan path,
|
|
25
|
+
it("includes logo, scan path, dashboard URL, and watch info", () => {
|
|
26
26
|
const text = formatDevBanner({
|
|
27
27
|
scanPath: "/tmp/components",
|
|
28
|
-
reportPath: "/tmp/components/public/
|
|
28
|
+
reportPath: "/tmp/components/public/dslinter-report.json",
|
|
29
29
|
apiPort: 7878,
|
|
30
30
|
apiAvailable: true,
|
|
31
31
|
dashboardUrl: "http://localhost:5173/",
|
|
32
|
-
bundledUrl: "http://127.0.0.1:7878/",
|
|
33
32
|
pollMs: 150,
|
|
34
33
|
});
|
|
35
34
|
expect(text).toContain(LOGO[0]);
|
|
36
35
|
expect(text).toContain(LOGO[1]);
|
|
37
36
|
expect(text).toContain("Scan path");
|
|
38
|
-
expect(text).toContain("Report file");
|
|
39
|
-
expect(text).toContain("
|
|
40
|
-
expect(text).
|
|
41
|
-
expect(text).not.
|
|
42
|
-
expect(text).toContain("
|
|
43
|
-
expect(text).toContain("
|
|
37
|
+
expect(text).not.toContain("Report file");
|
|
38
|
+
expect(text).toContain("Dashboard");
|
|
39
|
+
expect(text).toContain("http://localhost:5173/");
|
|
40
|
+
expect(text).not.toContain("Scanner API");
|
|
41
|
+
expect(text).not.toContain("dslinter-report.json");
|
|
42
|
+
expect(text).not.toContain("/events");
|
|
44
43
|
expect(text).toContain("polling every 150 ms");
|
|
45
|
-
expect(text).toContain("Open the
|
|
44
|
+
expect(text).toContain("Open the Dashboard in your browser");
|
|
46
45
|
});
|
|
47
46
|
|
|
48
|
-
it("shows
|
|
47
|
+
it("shows bundled URL as the dashboard when no separate dev server", () => {
|
|
49
48
|
const text = formatDevBanner({
|
|
50
49
|
scanPath: "/tmp/components",
|
|
51
|
-
reportPath: "/tmp/components/public/
|
|
50
|
+
reportPath: "/tmp/components/public/dslinter-report.json",
|
|
52
51
|
apiPort: 7878,
|
|
53
52
|
apiAvailable: true,
|
|
54
|
-
|
|
53
|
+
bundledUrl: "http://127.0.0.1:7878/",
|
|
55
54
|
pollMs: 150,
|
|
56
55
|
});
|
|
57
56
|
expect(text).toContain("Dashboard");
|
|
58
|
-
expect(text).toContain("http://
|
|
59
|
-
expect(text).toContain("
|
|
57
|
+
expect(text).toContain("http://127.0.0.1:7878/");
|
|
58
|
+
expect(text).not.toContain("Bundled UI");
|
|
59
|
+
expect(text).not.toContain("Scanner API");
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
it("marks
|
|
62
|
+
it("marks scanner unavailable when port is busy", () => {
|
|
63
63
|
const text = formatDevBanner({
|
|
64
64
|
scanPath: ".",
|
|
65
|
-
reportPath: "./public/
|
|
65
|
+
reportPath: "./public/dslinter-report.json",
|
|
66
66
|
apiPort: 7878,
|
|
67
67
|
apiAvailable: false,
|
|
68
68
|
dashboardUrl: "http://localhost:5174/",
|
|
69
69
|
});
|
|
70
|
+
expect(text).toContain("Scanner");
|
|
70
71
|
expect(text).toContain("unavailable");
|
|
72
|
+
expect(text).not.toContain("7878/");
|
|
71
73
|
expect(text).not.toContain("/events");
|
|
72
74
|
});
|
|
73
75
|
|
|
74
76
|
it("keeps right border aligned on every row", () => {
|
|
75
77
|
const text = formatDevBanner({
|
|
76
78
|
scanPath: "/very/long/path/that/could/push/the/box/wider/than/usual/Components",
|
|
77
|
-
reportPath: "/very/long/path/public/
|
|
79
|
+
reportPath: "/very/long/path/public/dslinter-report.json",
|
|
78
80
|
apiPort: 7878,
|
|
79
81
|
apiAvailable: false,
|
|
80
82
|
dashboardUrl: "http://localhost:5175/",
|