dslinter 0.0.8 → 0.0.11
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 +24 -2
- package/README.md +16 -11
- package/bin/dslinter.mjs +49 -16
- package/package.json +4 -4
- package/scripts/ensure-dslint.mjs +91 -50
- package/scripts/print-missing-scanner.mjs +25 -0
- package/scripts/resolve-dslint-binary.mjs +53 -6
- package/src/{shell → components}/DashboardCommandPalette.tsx +1 -1
- package/src/{shell → components}/Sidebar.tsx +2 -2
- package/src/dashboard/ComponentUsageDetails.tsx +1 -1
- package/src/dashboard/DashboardBody.tsx +1 -1
- package/src/resolve-dslint-binary.test.ts +31 -7
- package/src/shell/DashboardLayout.tsx +5 -5
- /package/src/{shell → components}/ComponentPlaygroundPane.tsx +0 -0
- /package/src/{shell → components}/EmptyCard.tsx +0 -0
- /package/src/{shell → components}/GovernancePane.tsx +0 -0
- /package/src/{shell → components}/PlaygroundA11yAndCode.tsx +0 -0
- /package/src/{shell → components}/PlaygroundControlField.tsx +0 -0
- /package/src/{shell → components}/PlaygroundControls.tsx +0 -0
- /package/src/{shell → components}/PlaygroundUsageCode.tsx +0 -0
- /package/src/{shell → components}/PlaygroundVariantMatrix.tsx +0 -0
- /package/src/{shell → components}/Section.tsx +0 -0
- /package/src/{shell → components}/TokensPane.tsx +0 -0
- /package/src/{shell → components}/controlApiTable.ts +0 -0
- /package/src/{shell → components}/playgroundUsageHighlight.ts +0 -0
- /package/src/{shell → components}/playgroundUsageTwoslash.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.0.11
|
|
4
|
+
|
|
5
|
+
[compare changes](https://github.com/jrmybtlr/DSLinter/compare/v0.0.10...v0.0.11)
|
|
6
|
+
|
|
7
|
+
### 🩹 Fixes
|
|
8
|
+
|
|
9
|
+
- Update repository references from DSLint to DSLinter ([2dbae8d](https://github.com/jrmybtlr/DSLinter/commit/2dbae8d))
|
|
10
|
+
|
|
11
|
+
### ❤️ Contributors
|
|
12
|
+
|
|
13
|
+
- Jeremy Butler <jeremy.butler@laravel.com>
|
|
14
|
+
|
|
15
|
+
## v0.0.10
|
|
16
|
+
|
|
17
|
+
[compare changes](https://github.com/jrmybtlr/DSLint/compare/v0.0.9...v0.0.10)
|
|
18
|
+
|
|
19
|
+
### 💅 Refactors
|
|
20
|
+
|
|
21
|
+
- Rename dslint to dslinter and update related configurations ([9f15898](https://github.com/jrmybtlr/DSLint/commit/9f15898))
|
|
22
|
+
|
|
23
|
+
### ❤️ Contributors
|
|
24
|
+
|
|
25
|
+
- Jeremy Butler <jeremy.butler@laravel.com>
|
|
26
|
+
|
|
3
27
|
## v0.0.8
|
|
4
28
|
|
|
5
29
|
[compare changes](https://github.com/jrmybtlr/DSLint/compare/v0.0.7...v0.0.8)
|
|
@@ -53,7 +77,6 @@
|
|
|
53
77
|
|
|
54
78
|
## v0.0.2
|
|
55
79
|
|
|
56
|
-
|
|
57
80
|
### 🚀 Enhancements
|
|
58
81
|
|
|
59
82
|
- Add DSLint MVP — JSX/Vue scan, usage rollup, governance rules ([4d64b76](https://github.com/jrmybtlr/DSLint/commit/4d64b76))
|
|
@@ -93,4 +116,3 @@
|
|
|
93
116
|
|
|
94
117
|
- Jeremy Butler <jeremy.butler@laravel.com>
|
|
95
118
|
- Cursor Agent ([@cursoragent](https://github.com/cursoragent))
|
|
96
|
-
|
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ The **`dslinter` binary** runs the **`dslint`** scanner with the same flags as t
|
|
|
25
25
|
|
|
26
26
|
On **`npm install dslinter`**, a **`postinstall`** script tries to download a **prebuilt `dslint`** for your OS/arch from this repo’s **GitHub Releases**, using the **same tag as the npm version** (for example npm `dslinter@0.0.6` → release **`v0.0.6`** and assets like `dslint-x86_64-unknown-linux-gnu`). The binary is stored under `node_modules/dslinter/vendor/` and `dslinter` / `npx dslinter` prefer it over `PATH`.
|
|
27
27
|
|
|
28
|
-
**Release workflow:** push git tag `v*` (after bumping the npm version) so [.github/workflows/release-dslint-binaries.yml](https://github.com/jrmybtlr/
|
|
28
|
+
**Release workflow:** push git tag `v*` (after bumping the npm version) so [.github/workflows/release-dslint-binaries.yml](https://github.com/jrmybtlr/DSLinter/blob/main/.github/workflows/release-dslint-binaries.yml) uploads the platform binaries, **then** publish `dslinter` to npm (or publish after the workflow finishes so installs resolve the assets).
|
|
29
29
|
|
|
30
30
|
Environment variables:
|
|
31
31
|
|
|
@@ -33,35 +33,40 @@ Environment variables:
|
|
|
33
33
|
|----------|---------|
|
|
34
34
|
| `DSLINT_SKIP_DOWNLOAD=1` | Skip postinstall download (air-gapped / you only use `PATH`). |
|
|
35
35
|
| `DSLINT_RELEASE_TAG` | Override release tag (default `v` + `dslinter` version from `package.json`). |
|
|
36
|
-
| `DSLINT_GITHUB_REPO` | Override `owner/repo` for downloads (default `jrmybtlr/
|
|
36
|
+
| `DSLINT_GITHUB_REPO` | Override `owner/repo` for downloads (default `jrmybtlr/DSLinter`). |
|
|
37
37
|
|
|
38
38
|
### How this differs from `oxlint`
|
|
39
39
|
|
|
40
40
|
**`oxlint`** on npm ships **Node native addons** as **`optionalDependencies`** (`@oxlint/binding-darwin-arm64`, …) built with **napi-rs** — each package is a small prebuilt library loaded by Node.
|
|
41
41
|
|
|
42
|
-
**`
|
|
42
|
+
**`dslinter`** is a **standalone executable**. The practical pattern here is **download on install** from **GitHub Releases** (similar in spirit to tools that pull a platform binary once), instead of publishing dozens of `@dslinter/binding-*` packages.
|
|
43
|
+
|
|
44
|
+
### Do not `cargo install dslint`
|
|
45
|
+
|
|
46
|
+
The crates.io crate **`dslint`** (v0.0.x) is a **different project** (design-file linting). It is **not** this design-system scanner. Installing it will break `npx dslinter` if it ends up on your `PATH`.
|
|
47
|
+
|
|
48
|
+
Use **`cargo install --git https://github.com/jrmybtlr/DSLinter dslinter --locked`** or set **`DSLINT_BIN`** to a local `target/release/dslinter` build.
|
|
43
49
|
|
|
44
50
|
### If there is no matching release asset yet
|
|
45
51
|
|
|
46
|
-
You’ll see a **warning** during install (install still succeeds)
|
|
52
|
+
You’ll see a **warning** during install (install still succeeds). **`dslinter`** will try to download on first run; if no GitHub release exists yet, you get a clear error (not a silent fallback to the wrong `dslint` on crates.io):
|
|
47
53
|
|
|
48
54
|
```bash
|
|
49
55
|
npx dslinter /path/to/repo --json -o dslint-report.json
|
|
50
56
|
```
|
|
51
57
|
|
|
52
|
-
| Distribution | How users get
|
|
58
|
+
| Distribution | How users get the scanner |
|
|
53
59
|
|--------------|-------------------------|
|
|
54
|
-
| **npm + GitHub Releases** | Default:
|
|
55
|
-
| **GitHub Releases** | Manual download of `
|
|
56
|
-
| **
|
|
60
|
+
| **npm + GitHub Releases** | Default: download when release `vX.Y.Z` includes your platform asset. |
|
|
61
|
+
| **GitHub Releases** | Manual download of `dslinter-*` from the release; run directly or set `DSLINT_BIN`. |
|
|
62
|
+
| **From source** | `cargo install --git https://github.com/jrmybtlr/DSLinter dslinter --locked` (not `cargo install dslint`). |
|
|
57
63
|
|
|
58
64
|
Typical usage:
|
|
59
65
|
|
|
60
66
|
```bash
|
|
61
|
-
dslint /path/to/repo --json -o dslint-report.json
|
|
62
|
-
# or --serve for live reload while developing a dashboard
|
|
63
|
-
# or equivalently (vendored or PATH):
|
|
64
67
|
dslinter /path/to/repo --json -o dslint-report.json
|
|
68
|
+
# or --serve for live reload while developing a dashboard
|
|
69
|
+
# (npm `npx dslinter` runs the same binary)
|
|
65
70
|
```
|
|
66
71
|
|
|
67
72
|
## Styles (Tailwind v4)
|
package/bin/dslinter.mjs
CHANGED
|
@@ -1,37 +1,70 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Runs the
|
|
3
|
+
* Runs the design-system scanner (`dslinter` binary from GitHub Releases or DSLINT_BIN).
|
|
4
|
+
* Does NOT use bare `dslint` on PATH — that name is a different crate on crates.io.
|
|
4
5
|
*/
|
|
5
6
|
import { spawnSync } from "node:child_process";
|
|
6
7
|
import { existsSync } from "node:fs";
|
|
7
8
|
import { dirname, join } from "node:path";
|
|
8
9
|
import { fileURLToPath } from "node:url";
|
|
9
|
-
import {
|
|
10
|
+
import { ensureDslintBinary } from "../scripts/ensure-dslint.mjs";
|
|
11
|
+
import {
|
|
12
|
+
SCANNER_VERSION_MARKER,
|
|
13
|
+
vendorBinaryPath,
|
|
14
|
+
} from "../scripts/resolve-dslint-binary.mjs";
|
|
10
15
|
|
|
11
16
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
17
|
const packageRoot = join(__dirname, "..");
|
|
13
18
|
|
|
14
19
|
const args = process.argv.slice(2);
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
const
|
|
21
|
+
function isOurScanner(binary) {
|
|
22
|
+
const help = spawnSync(binary, ["--help"], { encoding: "utf8" });
|
|
23
|
+
const out = `${help.stdout ?? ""}${help.stderr ?? ""}`;
|
|
24
|
+
return out.includes(SCANNER_VERSION_MARKER);
|
|
25
|
+
}
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
process.
|
|
27
|
+
async function resolveCommand() {
|
|
28
|
+
const fromEnv = process.env.DSLINT_BIN?.trim();
|
|
29
|
+
if (fromEnv) {
|
|
30
|
+
if (!existsSync(fromEnv)) {
|
|
31
|
+
process.stderr.write(`dslinter: DSLINT_BIN not found: ${fromEnv}\n`);
|
|
32
|
+
process.exit(127);
|
|
33
|
+
}
|
|
34
|
+
if (!isOurScanner(fromEnv)) {
|
|
35
|
+
process.stderr.write(
|
|
36
|
+
`dslinter: DSLINT_BIN does not look like the DSLint design-system scanner.\n` +
|
|
37
|
+
` Expected output containing "${SCANNER_VERSION_MARKER}".\n`,
|
|
38
|
+
);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
return fromEnv;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const vendored = vendorBinaryPath(packageRoot);
|
|
45
|
+
if (!existsSync(vendored)) {
|
|
46
|
+
await ensureDslintBinary(packageRoot, { quiet: true });
|
|
47
|
+
}
|
|
48
|
+
if (existsSync(vendored)) {
|
|
49
|
+
return vendored;
|
|
50
|
+
}
|
|
22
51
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
52
|
+
if (process.env.DSLINT_ALLOW_PATH === "1") {
|
|
53
|
+
const onPath = spawnSync("dslinter", ["--version"], { encoding: "utf8" });
|
|
54
|
+
if (onPath.status === 0 && `${onPath.stdout}`.includes(SCANNER_VERSION_MARKER)) {
|
|
55
|
+
return "dslinter";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
26
58
|
|
|
27
|
-
|
|
59
|
+
await import("../scripts/print-missing-scanner.mjs");
|
|
60
|
+
process.exit(127);
|
|
61
|
+
}
|
|
28
62
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
cargo install --path .
|
|
63
|
+
const cmd = await resolveCommand();
|
|
64
|
+
const child = spawnSync(cmd, args, { stdio: "inherit" });
|
|
32
65
|
|
|
33
|
-
|
|
34
|
-
`);
|
|
66
|
+
if (child.error && "code" in child.error && child.error.code === "ENOENT") {
|
|
67
|
+
process.stderr.write(`dslinter: failed to execute ${cmd}\n`);
|
|
35
68
|
process.exit(127);
|
|
36
69
|
}
|
|
37
70
|
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dslinter",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "DSLinter dashboard UI: playground shell, token wall, and governance panels (consumes dslint-report.json).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/jrmybtlr/
|
|
9
|
+
"url": "https://github.com/jrmybtlr/DSLinter.git",
|
|
10
10
|
"directory": "packages/dashboard"
|
|
11
11
|
},
|
|
12
12
|
"bugs": {
|
|
13
|
-
"url": "https://github.com/jrmybtlr/
|
|
13
|
+
"url": "https://github.com/jrmybtlr/DSLinter/issues"
|
|
14
14
|
},
|
|
15
|
-
"homepage": "https://github.com/jrmybtlr/
|
|
15
|
+
"homepage": "https://github.com/jrmybtlr/DSLinter#readme",
|
|
16
16
|
"keywords": [
|
|
17
17
|
"dslinter",
|
|
18
18
|
"design-system",
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Best-effort download of the prebuilt `
|
|
3
|
-
*
|
|
4
|
-
* is missing (no release yet / offline) so installs never fail.
|
|
2
|
+
* Best-effort download of the prebuilt `dslinter` CLI for this platform.
|
|
3
|
+
* Used by postinstall and on first `dslinter` / `npx dslinter` invocation.
|
|
5
4
|
*/
|
|
6
5
|
import { readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
7
6
|
import { chmod, mkdir, stat } from "node:fs/promises";
|
|
8
7
|
import { dirname, join } from "node:path";
|
|
9
8
|
import { fileURLToPath } from "node:url";
|
|
10
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
githubRepoFromPackage,
|
|
11
|
+
releaseAssetBaseName,
|
|
12
|
+
vendorBinaryPath,
|
|
13
|
+
} from "./resolve-dslint-binary.mjs";
|
|
11
14
|
|
|
12
15
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
-
const
|
|
16
|
+
const defaultPackageRoot = join(__dirname, "..");
|
|
14
17
|
|
|
15
18
|
async function pathExists(p) {
|
|
16
19
|
try {
|
|
@@ -21,8 +24,10 @@ async function pathExists(p) {
|
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
function readPackageVersion() {
|
|
25
|
-
const pkg = JSON.parse(
|
|
27
|
+
function readPackageVersion(packageRoot) {
|
|
28
|
+
const pkg = JSON.parse(
|
|
29
|
+
readFileSync(join(packageRoot, "package.json"), "utf8"),
|
|
30
|
+
);
|
|
26
31
|
return pkg.version;
|
|
27
32
|
}
|
|
28
33
|
|
|
@@ -32,65 +37,101 @@ function releaseTag(version) {
|
|
|
32
37
|
return `v${version}`;
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
function releaseRepo(packageRoot) {
|
|
41
|
+
const override = process.env.DSLINT_GITHUB_REPO?.trim();
|
|
42
|
+
if (override) return override;
|
|
43
|
+
return githubRepoFromPackage(packageRoot);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function assetUrl(packageRoot, tag, asset) {
|
|
47
|
+
return `https://github.com/${releaseRepo(packageRoot)}/releases/download/${tag}/${asset}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {string} packageRoot
|
|
52
|
+
* @param {{ quiet?: boolean }} [opts]
|
|
53
|
+
* @returns {Promise<boolean>} true if vendored binary exists after this call
|
|
54
|
+
*/
|
|
55
|
+
export async function ensureDslintBinary(packageRoot = defaultPackageRoot, opts = {}) {
|
|
56
|
+
const { quiet = false } = opts;
|
|
57
|
+
const log = quiet ? () => {} : console.warn.bind(console);
|
|
58
|
+
|
|
59
|
+
if (process.env.DSLINT_SKIP_DOWNLOAD === "1") {
|
|
60
|
+
return pathExists(vendorBinaryPath(packageRoot));
|
|
61
|
+
}
|
|
37
62
|
|
|
38
63
|
const dest = vendorBinaryPath(packageRoot);
|
|
39
|
-
if (await pathExists(dest)) return;
|
|
64
|
+
if (await pathExists(dest)) return true;
|
|
40
65
|
|
|
41
66
|
const asset = releaseAssetBaseName();
|
|
42
67
|
if (!asset) {
|
|
43
|
-
|
|
44
|
-
`[dslinter] No prebuilt
|
|
68
|
+
log(
|
|
69
|
+
`[dslinter] No prebuilt scanner for ${process.platform}-${process.arch}.`,
|
|
45
70
|
);
|
|
46
|
-
return;
|
|
71
|
+
return false;
|
|
47
72
|
}
|
|
48
73
|
|
|
49
|
-
const version = readPackageVersion();
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
74
|
+
const version = readPackageVersion(packageRoot);
|
|
75
|
+
const tagsToTry = [releaseTag(version)];
|
|
76
|
+
if (process.env.DSLINT_USE_LATEST_RELEASE !== "0") {
|
|
77
|
+
tagsToTry.push("latest");
|
|
78
|
+
}
|
|
53
79
|
|
|
54
80
|
const vendorDir = join(packageRoot, "vendor");
|
|
55
81
|
await mkdir(vendorDir, { recursive: true });
|
|
56
|
-
|
|
57
82
|
const tmp = `${dest}.part`;
|
|
58
83
|
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
if (res.status === 404) {
|
|
62
|
-
console.warn(
|
|
63
|
-
`[dslinter] No GitHub release asset at ${url}\n` +
|
|
64
|
-
` Create release ${tag} with ${asset} (see .github/workflows/release-dslint-binaries.yml), or install dslint via cargo / PATH.`,
|
|
65
|
-
);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
if (!res.ok) {
|
|
69
|
-
console.warn(`[dslinter] Download failed (${res.status}): ${url}`);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const buf = Buffer.from(await res.arrayBuffer());
|
|
74
|
-
writeFileSync(tmp, buf);
|
|
75
|
-
|
|
84
|
+
for (const tag of tagsToTry) {
|
|
85
|
+
const url = assetUrl(packageRoot, tag, asset);
|
|
76
86
|
try {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
const res = await fetch(url, { redirect: "follow" });
|
|
88
|
+
if (res.status === 404) continue;
|
|
89
|
+
if (!res.ok) {
|
|
90
|
+
log(`[dslinter] Download failed (${res.status}): ${url}`);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
82
93
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
95
|
+
writeFileSync(tmp, buf);
|
|
96
|
+
try {
|
|
97
|
+
if (await pathExists(dest)) unlinkSync(dest);
|
|
98
|
+
} catch {
|
|
99
|
+
/* ignore */
|
|
100
|
+
}
|
|
101
|
+
renameSync(tmp, dest);
|
|
102
|
+
if (process.platform !== "win32") {
|
|
103
|
+
await chmod(dest, 0o755);
|
|
104
|
+
}
|
|
105
|
+
if (tag === "latest" && !quiet) {
|
|
106
|
+
log(
|
|
107
|
+
`[dslinter] Installed scanner from latest GitHub release (no asset for npm v${version}).`,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
} catch (err) {
|
|
112
|
+
log(
|
|
113
|
+
`[dslinter] Could not download: ${err instanceof Error ? err.message : err}`,
|
|
114
|
+
);
|
|
115
|
+
try {
|
|
116
|
+
unlinkSync(tmp);
|
|
117
|
+
} catch {
|
|
118
|
+
/* ignore */
|
|
119
|
+
}
|
|
92
120
|
}
|
|
93
121
|
}
|
|
122
|
+
|
|
123
|
+
log(
|
|
124
|
+
`[dslinter] No GitHub release with asset "${asset}" (tried ${tagsToTry.join(", ")}).\n` +
|
|
125
|
+
` Publish tag ${releaseTag(version)} with workflow release-dslint-binaries.yml, or set DSLINT_BIN to a local build.`,
|
|
126
|
+
);
|
|
127
|
+
return false;
|
|
94
128
|
}
|
|
95
129
|
|
|
96
|
-
|
|
130
|
+
const isMain =
|
|
131
|
+
process.argv[1] &&
|
|
132
|
+
fileURLToPath(import.meta.url) === process.argv[1];
|
|
133
|
+
|
|
134
|
+
if (isMain) {
|
|
135
|
+
const ok = await ensureDslintBinary();
|
|
136
|
+
process.exit(ok ? 0 : 0);
|
|
137
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const packageRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
6
|
+
const version = JSON.parse(
|
|
7
|
+
readFileSync(join(packageRoot, "package.json"), "utf8"),
|
|
8
|
+
).version;
|
|
9
|
+
|
|
10
|
+
process.stderr.write(`dslinter: scanner binary not available.
|
|
11
|
+
|
|
12
|
+
This npm package is NOT the same as \`cargo install dslint\` on crates.io (that is a
|
|
13
|
+
different "design file" linter and will crash or misbehave).
|
|
14
|
+
|
|
15
|
+
To run the design-system scanner:
|
|
16
|
+
|
|
17
|
+
1. Re-run after a GitHub release exists for v${version} (prebuilt download), or
|
|
18
|
+
2. Build from this repo and point at it:
|
|
19
|
+
cargo install --git https://github.com/jrmybtlr/DSLinter dslinter --locked
|
|
20
|
+
export DSLINT_BIN="$(command -v dslinter)"
|
|
21
|
+
npx dslinter ...
|
|
22
|
+
3. Or set DSLINT_BIN to your local target/release/dslinter
|
|
23
|
+
|
|
24
|
+
Releases: https://github.com/jrmybtlr/DSLinter/releases
|
|
25
|
+
`);
|
|
@@ -1,5 +1,38 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import { join } from "node:path";
|
|
2
3
|
|
|
4
|
+
/** CLI binary name (avoids collision with unrelated `dslint` on crates.io). */
|
|
5
|
+
export const CLI_BINARY_NAME = "dslinter";
|
|
6
|
+
|
|
7
|
+
/** Fallback when package.json has no parseable `repository` field. */
|
|
8
|
+
export const DEFAULT_GITHUB_REPO = "jrmybtlr/DSLinter";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string | { type?: string; url?: string } | undefined} repository
|
|
12
|
+
* @returns {string | null} `owner/repo`
|
|
13
|
+
*/
|
|
14
|
+
export function parseGitHubRepo(repository) {
|
|
15
|
+
if (!repository) return null;
|
|
16
|
+
const url = typeof repository === "string" ? repository : repository.url;
|
|
17
|
+
if (!url) return null;
|
|
18
|
+
const m = String(url).match(/github\.com[/:]([^/]+)\/([^/.]+?)(?:\.git)?\/?$/i);
|
|
19
|
+
return m ? `${m[1]}/${m[2]}` : null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {string} packageRoot
|
|
24
|
+
*/
|
|
25
|
+
export function githubRepoFromPackage(packageRoot) {
|
|
26
|
+
try {
|
|
27
|
+
const pkg = JSON.parse(
|
|
28
|
+
readFileSync(join(packageRoot, "package.json"), "utf8"),
|
|
29
|
+
);
|
|
30
|
+
return parseGitHubRepo(pkg.repository) ?? DEFAULT_GITHUB_REPO;
|
|
31
|
+
} catch {
|
|
32
|
+
return DEFAULT_GITHUB_REPO;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
3
36
|
/**
|
|
4
37
|
* Maps the current OS/arch to the GitHub release asset basename (must match CI upload names).
|
|
5
38
|
* @param {NodeJS.Process} [proc]
|
|
@@ -7,11 +40,21 @@ import { join } from "node:path";
|
|
|
7
40
|
*/
|
|
8
41
|
export function releaseAssetBaseName(proc = process) {
|
|
9
42
|
const { platform, arch } = proc;
|
|
10
|
-
if (platform === "darwin" && arch === "arm64")
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (platform === "
|
|
14
|
-
|
|
43
|
+
if (platform === "darwin" && arch === "arm64") {
|
|
44
|
+
return "dslinter-aarch64-apple-darwin";
|
|
45
|
+
}
|
|
46
|
+
if (platform === "darwin" && arch === "x64") {
|
|
47
|
+
return "dslinter-x86_64-apple-darwin";
|
|
48
|
+
}
|
|
49
|
+
if (platform === "linux" && arch === "x64") {
|
|
50
|
+
return "dslinter-x86_64-unknown-linux-gnu";
|
|
51
|
+
}
|
|
52
|
+
if (platform === "linux" && arch === "arm64") {
|
|
53
|
+
return "dslinter-aarch64-unknown-linux-gnu";
|
|
54
|
+
}
|
|
55
|
+
if (platform === "win32" && arch === "x64") {
|
|
56
|
+
return "dslinter-x86_64-pc-windows-msvc.exe";
|
|
57
|
+
}
|
|
15
58
|
return null;
|
|
16
59
|
}
|
|
17
60
|
|
|
@@ -20,6 +63,10 @@ export function releaseAssetBaseName(proc = process) {
|
|
|
20
63
|
* @param {NodeJS.Process} [proc]
|
|
21
64
|
*/
|
|
22
65
|
export function vendorBinaryPath(packageRoot, proc = process) {
|
|
23
|
-
const name =
|
|
66
|
+
const name =
|
|
67
|
+
proc.platform === "win32" ? `${CLI_BINARY_NAME}.exe` : CLI_BINARY_NAME;
|
|
24
68
|
return join(packageRoot, "vendor", name);
|
|
25
69
|
}
|
|
70
|
+
|
|
71
|
+
/** Our scanner prints this in `dslinter --version` help output (clap about line). */
|
|
72
|
+
export const SCANNER_VERSION_MARKER = "design system linting";
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "@/components/ui/command";
|
|
11
11
|
|
|
12
12
|
import type { PlaygroundEntry } from "../types/playground";
|
|
13
|
-
import type { HashRoute } from "
|
|
13
|
+
import type { HashRoute } from "../shell/hashRoute";
|
|
14
14
|
|
|
15
15
|
type Props = {
|
|
16
16
|
entries: PlaygroundEntry[];
|
|
@@ -3,8 +3,8 @@ import { IconMoon, IconSearch, IconSun } from "@/components/icons";
|
|
|
3
3
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
|
4
4
|
|
|
5
5
|
import type { PlaygroundEntry } from "../types/playground";
|
|
6
|
-
import type { HashRoute } from "
|
|
7
|
-
import type { DashboardThemePreference } from "
|
|
6
|
+
import type { HashRoute } from "../shell/hashRoute";
|
|
7
|
+
import type { DashboardThemePreference } from "../shell/DashboardLayout";
|
|
8
8
|
|
|
9
9
|
type Props = {
|
|
10
10
|
entries: PlaygroundEntry[];
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import type { UsageLocation, WorkspaceReport } from "../types/report";
|
|
11
11
|
import { usageMap } from "./aggregate";
|
|
12
12
|
import { shortPath } from "./paths";
|
|
13
|
-
import { EmptyCard } from "../
|
|
13
|
+
import { EmptyCard } from "../components/EmptyCard";
|
|
14
14
|
import { InlineCode } from "@/components/InlineCode";
|
|
15
15
|
|
|
16
16
|
function formatCallSiteProps(loc: UsageLocation): string {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { describe, expect, it } from "vitest";
|
|
3
3
|
import {
|
|
4
|
+
CLI_BINARY_NAME,
|
|
5
|
+
DEFAULT_GITHUB_REPO,
|
|
6
|
+
parseGitHubRepo,
|
|
4
7
|
releaseAssetBaseName,
|
|
5
8
|
vendorBinaryPath,
|
|
6
9
|
} from "../scripts/resolve-dslint-binary.mjs";
|
|
@@ -9,22 +12,43 @@ function proc(platform: string, arch: string): NodeJS.Process {
|
|
|
9
12
|
return { platform, arch } as NodeJS.Process;
|
|
10
13
|
}
|
|
11
14
|
|
|
15
|
+
describe("parseGitHubRepo", () => {
|
|
16
|
+
it("parses https repository url", () => {
|
|
17
|
+
expect(
|
|
18
|
+
parseGitHubRepo("https://github.com/jrmybtlr/DSLinter.git"),
|
|
19
|
+
).toBe("jrmybtlr/DSLinter");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("parses repository object", () => {
|
|
23
|
+
expect(
|
|
24
|
+
parseGitHubRepo({
|
|
25
|
+
type: "git",
|
|
26
|
+
url: "git+https://github.com/jrmybtlr/DSLinter.git",
|
|
27
|
+
}),
|
|
28
|
+
).toBe("jrmybtlr/DSLinter");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("defaults constant points at DSLinter", () => {
|
|
32
|
+
expect(DEFAULT_GITHUB_REPO).toBe("jrmybtlr/DSLinter");
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
12
36
|
describe("releaseAssetBaseName", () => {
|
|
13
37
|
it("maps darwin arm64", () => {
|
|
14
38
|
expect(releaseAssetBaseName(proc("darwin", "arm64"))).toBe(
|
|
15
|
-
"
|
|
39
|
+
"dslinter-aarch64-apple-darwin",
|
|
16
40
|
);
|
|
17
41
|
});
|
|
18
42
|
|
|
19
43
|
it("maps linux x64", () => {
|
|
20
44
|
expect(releaseAssetBaseName(proc("linux", "x64"))).toBe(
|
|
21
|
-
"
|
|
45
|
+
"dslinter-x86_64-unknown-linux-gnu",
|
|
22
46
|
);
|
|
23
47
|
});
|
|
24
48
|
|
|
25
49
|
it("maps win32 x64", () => {
|
|
26
50
|
expect(releaseAssetBaseName(proc("win32", "x64"))).toBe(
|
|
27
|
-
"
|
|
51
|
+
"dslinter-x86_64-pc-windows-msvc.exe",
|
|
28
52
|
);
|
|
29
53
|
});
|
|
30
54
|
|
|
@@ -34,15 +58,15 @@ describe("releaseAssetBaseName", () => {
|
|
|
34
58
|
});
|
|
35
59
|
|
|
36
60
|
describe("vendorBinaryPath", () => {
|
|
37
|
-
it("uses
|
|
61
|
+
it("uses dslinter.exe on Windows", () => {
|
|
38
62
|
expect(vendorBinaryPath(join("/", "pkg"), proc("win32", "x64"))).toBe(
|
|
39
|
-
join("/", "pkg", "vendor",
|
|
63
|
+
join("/", "pkg", "vendor", `${CLI_BINARY_NAME}.exe`),
|
|
40
64
|
);
|
|
41
65
|
});
|
|
42
66
|
|
|
43
|
-
it("uses
|
|
67
|
+
it("uses dslinter on Unix", () => {
|
|
44
68
|
expect(vendorBinaryPath(join("/", "pkg"), proc("linux", "x64"))).toBe(
|
|
45
|
-
join("/", "pkg", "vendor",
|
|
69
|
+
join("/", "pkg", "vendor", CLI_BINARY_NAME),
|
|
46
70
|
);
|
|
47
71
|
});
|
|
48
72
|
});
|
|
@@ -12,11 +12,11 @@ import type { TokenCatalog } from "../types/tokenCatalog";
|
|
|
12
12
|
import type { DslinterReportState } from "../dashboard/useWorkspaceReport";
|
|
13
13
|
import { Button } from "@/components/ui/button";
|
|
14
14
|
import { cn } from "../lib/utils";
|
|
15
|
-
import { ComponentPlaygroundPane } from "
|
|
16
|
-
import { GovernancePane } from "
|
|
17
|
-
import { Sidebar } from "
|
|
18
|
-
import { TokensPane } from "
|
|
19
|
-
import { DashboardCommandPalette } from "
|
|
15
|
+
import { ComponentPlaygroundPane } from "../components/ComponentPlaygroundPane";
|
|
16
|
+
import { GovernancePane } from "../components/GovernancePane";
|
|
17
|
+
import { Sidebar } from "../components/Sidebar";
|
|
18
|
+
import { TokensPane } from "../components/TokensPane";
|
|
19
|
+
import { DashboardCommandPalette } from "../components/DashboardCommandPalette";
|
|
20
20
|
import { useHashRoute } from "./useHashRoute";
|
|
21
21
|
|
|
22
22
|
const STORAGE_KEY = "dslinter-dashboard-theme";
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|