dslinter 0.1.13 → 0.2.2
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 +72 -0
- package/README.md +50 -29
- 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 +72 -10
- package/bin/lib/project-root.test.mjs +32 -1
- 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 +128 -9
- package/bin/lib/scaffold-config.test.mjs +24 -2
- 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 +55 -21
- package/bin/modes/init.mjs +3 -22
- package/bin/modes/init.test.mjs +1 -1
- 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 +212 -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 +91 -3
- package/vite/collectScanModules.ts +94 -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-Bm7yfyC-.css +0 -1
- package/dashboard-dist/assets/DashboardLayoutAuto-DgwO_itB.js +0 -1
- package/dashboard-dist/assets/index-Cbv7vXvH.css +0 -1
- package/dashboard-dist/assets/index-e20cwqnb.js +0 -206
- package/src/components/playgroundUsageTwoslash.ts +0 -69
- package/templates/vite.dslint-scan-alias.snippet.ts +0 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.2.2
|
|
4
|
+
|
|
5
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.2.1...v0.2.2)
|
|
6
|
+
|
|
7
|
+
### ✅ Tests
|
|
8
|
+
|
|
9
|
+
- **collectScanModules:** Enhance case sensitivity tests for include_dirs ([32c2065](https://github.com/jrmybtlr/DSLinter/commit/32c2065))
|
|
10
|
+
|
|
11
|
+
### ❤️ Contributors
|
|
12
|
+
|
|
13
|
+
- Jeremy Butler <jeremy.butler@laravel.com>
|
|
14
|
+
|
|
15
|
+
## v0.2.1
|
|
16
|
+
|
|
17
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.2.0...v0.2.1)
|
|
18
|
+
|
|
19
|
+
### 🩹 Fixes
|
|
20
|
+
|
|
21
|
+
- **ci:** Build NAPI and demo report before publish tests ([fdf497d](https://github.com/jrmybtlr/DSLinter/commit/fdf497d))
|
|
22
|
+
- **report-cache:** Improve report path validation by ensuring report root matches project root ([7510dde](https://github.com/jrmybtlr/DSLinter/commit/7510dde))
|
|
23
|
+
|
|
24
|
+
### 💅 Refactors
|
|
25
|
+
|
|
26
|
+
- Enhance path resolution for include directories and improve case sensitivity handling ([22c96fb](https://github.com/jrmybtlr/DSLinter/commit/22c96fb))
|
|
27
|
+
|
|
28
|
+
### ❤️ Contributors
|
|
29
|
+
|
|
30
|
+
- Jeremy Butler <jeremy.butler@laravel.com>
|
|
31
|
+
|
|
32
|
+
## v0.2.0
|
|
33
|
+
|
|
34
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.1.13...v0.2.0)
|
|
35
|
+
|
|
36
|
+
### 🚀 Enhancements
|
|
37
|
+
|
|
38
|
+
- **website:** Switch deploy config from pages to workers ([22d7e35](https://github.com/jrmybtlr/DSLinter/commit/22d7e35))
|
|
39
|
+
- **playground:** Add user info playground component and enhance controls handling ([625f7c2](https://github.com/jrmybtlr/DSLinter/commit/625f7c2))
|
|
40
|
+
|
|
41
|
+
### 🔥 Performance
|
|
42
|
+
|
|
43
|
+
- Precompute newline_offsets once in analyze_vue_file, pass to merge_template_usages ([a2839b3](https://github.com/jrmybtlr/DSLinter/commit/a2839b3))
|
|
44
|
+
|
|
45
|
+
### 🩹 Fixes
|
|
46
|
+
|
|
47
|
+
- **dashboard:** Address PR review feedback on publish files and API export ([d3a1f1b](https://github.com/jrmybtlr/DSLinter/commit/d3a1f1b))
|
|
48
|
+
- Import website main stylesheet in entrypoint ([79fa1ec](https://github.com/jrmybtlr/DSLinter/commit/79fa1ec))
|
|
49
|
+
- Remove duplicate typescript devDependency in dashboard package ([03e3dc1](https://github.com/jrmybtlr/DSLinter/commit/03e3dc1))
|
|
50
|
+
- Address review comments - remove duplicate typescript dep, add .d.mts declaration, remove dead code ([cbfd7ab](https://github.com/jrmybtlr/DSLinter/commit/cbfd7ab))
|
|
51
|
+
|
|
52
|
+
### 💅 Refactors
|
|
53
|
+
|
|
54
|
+
- **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))
|
|
55
|
+
- **ts:** Split playground module, useRef cancellation, Set dedup, useMemo fixes, DashboardLayout, Sidebar, barrel index ([d57a673](https://github.com/jrmybtlr/DSLinter/commit/d57a673))
|
|
56
|
+
|
|
57
|
+
### 📖 Documentation
|
|
58
|
+
|
|
59
|
+
- Update README config options ([5f2be14](https://github.com/jrmybtlr/DSLinter/commit/5f2be14))
|
|
60
|
+
- Remove trailing spaces in README ([1fc4c1d](https://github.com/jrmybtlr/DSLinter/commit/1fc4c1d))
|
|
61
|
+
|
|
62
|
+
### 🏡 Chore
|
|
63
|
+
|
|
64
|
+
- **release:** V0.1.13 ([3cd1a20](https://github.com/jrmybtlr/DSLinter/commit/3cd1a20))
|
|
65
|
+
- **dashboard:** Remove dead code and dedupe helpers ([cb41bcd](https://github.com/jrmybtlr/DSLinter/commit/cb41bcd))
|
|
66
|
+
- Begin optimisation pass over src/ and packages/dashboard ([8ec1a34](https://github.com/jrmybtlr/DSLinter/commit/8ec1a34))
|
|
67
|
+
- Plan cloudflare workers website deploy ([affabf5](https://github.com/jrmybtlr/DSLinter/commit/affabf5))
|
|
68
|
+
- Add semver as a dev dependency and update pnpm lockfile ([18afb12](https://github.com/jrmybtlr/DSLinter/commit/18afb12))
|
|
69
|
+
|
|
70
|
+
### ❤️ Contributors
|
|
71
|
+
|
|
72
|
+
- Jeremy Butler <jeremy.butler@laravel.com>
|
|
73
|
+
- Cursor Agent ([@cursoragent](https://github.com/cursoragent))
|
|
74
|
+
|
|
3
75
|
## v0.1.13
|
|
4
76
|
|
|
5
77
|
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.1.12...v0.1.13)
|
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,43 +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 `
|
|
59
|
-
|
|
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 |
|
|
60
71
|
|
|
61
72
|
### Zero-config live previews (recommended)
|
|
62
73
|
|
|
63
|
-
**`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.
|
|
64
75
|
|
|
65
|
-
|
|
66
|
-
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.
|
|
67
77
|
|
|
68
|
-
|
|
69
|
-
reportUrl: "/dslint-report.json",
|
|
70
|
-
watchUrl: "/events",
|
|
71
|
-
});
|
|
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.
|
|
72
79
|
|
|
73
|
-
|
|
74
|
-
```
|
|
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.
|
|
75
81
|
|
|
76
|
-
|
|
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`.
|
|
77
83
|
|
|
78
84
|
**Direct `vite --mode serve`:** add one line to `vite.config.ts`:
|
|
79
85
|
|
|
@@ -85,12 +91,27 @@ export default defineConfig({
|
|
|
85
91
|
});
|
|
86
92
|
```
|
|
87
93
|
|
|
88
|
-
The plugin sets `
|
|
94
|
+
The plugin sets `DSLINTER_SCAN_ROOT` from the environment (set by `npx dslinter`) or defaults to `process.cwd()`.
|
|
89
95
|
|
|
90
96
|
### Consumer Vite (Laravel, Inertia, existing `@/*` aliases)
|
|
91
97
|
|
|
92
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.
|
|
93
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
|
+
|
|
94
115
|
## Styles (Tailwind v4)
|
|
95
116
|
|
|
96
117
|
1. In your app CSS, load Tailwind, then point Tailwind at this package so utility scanning picks up dashboard classes:
|
|
@@ -113,7 +134,7 @@ Use **`autoPlayground`** (above) for zero-config previews. Optionally scaffold a
|
|
|
113
134
|
- `npx dslinter init` → `src/playground/buildRegistry.ts`
|
|
114
135
|
- `npx dslinter init --laravel` → `resources/js/playground/buildRegistry.ts`
|
|
115
136
|
|
|
116
|
-
`npx dslinter init` now also scaffolds a starter `.
|
|
137
|
+
`npx dslinter init` now also scaffolds a starter `.dslinter.json` (unless one already exists), including:
|
|
117
138
|
- `include_dirs` (directory scope for discovery)
|
|
118
139
|
- `ignore_globs` (file/directory ignores)
|
|
119
140
|
- `css_entrypoints` (main CSS entry files for token analysis)
|
|
@@ -123,7 +144,7 @@ import { useMemo } from "react";
|
|
|
123
144
|
import { DashboardLayout, useWorkspaceReport } from "dslinter";
|
|
124
145
|
import { buildPlaygroundEntries } from "./playground/buildRegistry";
|
|
125
146
|
|
|
126
|
-
const dslinterReport = useWorkspaceReport({ reportUrl: "/
|
|
147
|
+
const dslinterReport = useWorkspaceReport({ reportUrl: "/dslinter-report.json", watchUrl: "/events" });
|
|
127
148
|
const playgroundEntries = useMemo(
|
|
128
149
|
() => buildPlaygroundEntries(dslinterReport.report),
|
|
129
150
|
[dslinterReport.report],
|
|
@@ -143,7 +164,7 @@ Run the scanner from the **project root** (`npx dslinter .`) so `playgrounds[].r
|
|
|
143
164
|
- **`autoPlayground`** (recommended) — or **`playgroundEntries`** from a custom registry / `usePlaygroundFromReport`.
|
|
144
165
|
- **`playgroundJoinSkips`** (optional) — auto-filled when using `autoPlayground`.
|
|
145
166
|
- **`tokenCatalog`** — token wall data (see `demo/src/tokenCatalog.ts`).
|
|
146
|
-
- **`dslinterReport`** — from `useWorkspaceReport({ reportUrl: "/
|
|
167
|
+
- **`dslinterReport`** — from `useWorkspaceReport({ reportUrl: "/dslinter-report.json", ... })`.
|
|
147
168
|
|
|
148
169
|
```tsx
|
|
149
170
|
import { useMemo } from "react";
|
|
@@ -156,7 +177,7 @@ import { tokenCatalog } from "./tokenCatalog";
|
|
|
156
177
|
|
|
157
178
|
export default function App() {
|
|
158
179
|
const dslinterReport = useWorkspaceReport({
|
|
159
|
-
reportUrl: "/
|
|
180
|
+
reportUrl: "/dslinter-report.json",
|
|
160
181
|
refreshIntervalMs: 5000,
|
|
161
182
|
});
|
|
162
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/",
|