@designesy/score 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/engine.d.ts +3 -2
- package/dist/engine.js +31 -5
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @designesy/score
|
|
2
2
|
|
|
3
|
-
Standalone 44-check design-contract scoring engine. Fetches a URL, extracts CSS + `:root` tokens, runs all checks locally, with **no server required**.
|
|
3
|
+
Standalone 44-check design-contract scoring engine. Fetches a URL, extracts CSS + `:root` tokens, runs all checks locally, with **no server required**. No required dependencies.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -90,12 +90,14 @@ Plus 12 anti-slop deductions (S1 to S12) and 7 originality lifts (O1 to O7).
|
|
|
90
90
|
|
|
91
91
|
Auto-detect: `designesy.org` → contract, everything else → universal.
|
|
92
92
|
|
|
93
|
-
##
|
|
93
|
+
## Dependencies
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
The engine uses only Node.js built-ins:
|
|
96
96
|
- `node:https` for URL fetching (avoids the Windows libuv/undici crash)
|
|
97
97
|
- `node:dns` for SSRF guard (DNS resolution validation)
|
|
98
|
-
- No `ipaddr.js`, no `undici`, no `fetch()
|
|
98
|
+
- No `ipaddr.js`, no `undici`, no `fetch()`
|
|
99
|
+
|
|
100
|
+
One optional dependency: Google's [`@google/design.md`](https://github.com/google-labs-code/design.md) linter (Apache-2.0), the version the hosted engine runs. v37 uses it to lint a site's `/DESIGN.md`. npm installs it by default, `npx` included. Installed without it (`npm install --omit=optional`), v37 reports MANUAL (not run, weight 0) for a site that serves a DESIGN.md, and every other check is unchanged.
|
|
99
101
|
|
|
100
102
|
## SSRF guard
|
|
101
103
|
|
package/dist/engine.d.ts
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* browser), computes a weighted score (0-100), assigns a letter grade (A-F),
|
|
7
7
|
* and applies anti-slop deductions + originality lifts.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* libuv crash during process exit.
|
|
9
|
+
* No required dependencies. Uses node:https (not fetch/undici) to avoid the
|
|
10
|
+
* Windows libuv crash during process exit. One optional dependency,
|
|
11
|
+
* @google/design.md, lints /DESIGN.md for v37; without it v37 is MANUAL.
|
|
11
12
|
*
|
|
12
13
|
* Extracted from apps/site/app/api/score/route.ts — same engine, same checks,
|
|
13
14
|
* same scoring math. The API route wraps this module; the CLI calls it directly.
|
package/dist/engine.js
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* browser), computes a weighted score (0-100), assigns a letter grade (A-F),
|
|
7
7
|
* and applies anti-slop deductions + originality lifts.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* libuv crash during process exit.
|
|
9
|
+
* No required dependencies. Uses node:https (not fetch/undici) to avoid the
|
|
10
|
+
* Windows libuv crash during process exit. One optional dependency,
|
|
11
|
+
* @google/design.md, lints /DESIGN.md for v37; without it v37 is MANUAL.
|
|
11
12
|
*
|
|
12
13
|
* Extracted from apps/site/app/api/score/route.ts — same engine, same checks,
|
|
13
14
|
* same scoring math. The API route wraps this module; the CLI calls it directly.
|
|
@@ -3735,7 +3736,7 @@ async function checkDesignMdSpec(targetUrl) {
|
|
|
3735
3736
|
// package missing from THIS runtime, so the same page scored lower from the
|
|
3736
3737
|
// npm CLI than from the API. Unverified-here is what MANUAL means (v02,
|
|
3737
3738
|
// v04, v21): weight 0, resolved by a run that has the linter.
|
|
3738
|
-
const msg = e instanceof Error ? e.message : 'unknown error';
|
|
3739
|
+
const msg = sanitizeErrorText(e instanceof Error ? e.message : 'unknown error');
|
|
3739
3740
|
return { id: 'v37', item: ITEM, category: CATEGORY, status: 'MANUAL', detail: `/DESIGN.md fetched but linter unavailable: ${msg}. The @google/design.md package may not be installed in this runtime; run the full audit to resolve.` };
|
|
3740
3741
|
}
|
|
3741
3742
|
try {
|
|
@@ -3753,10 +3754,35 @@ async function checkDesignMdSpec(targetUrl) {
|
|
|
3753
3754
|
// Distinct from the branch above: the linter LOADED and then threw, so the
|
|
3754
3755
|
// file's format is unsupported rather than the runtime being incomplete.
|
|
3755
3756
|
// Both WARN, but the messages point at different fixes.
|
|
3756
|
-
const msg = e instanceof Error ? e.message : 'unknown error';
|
|
3757
|
+
const msg = sanitizeErrorText(e instanceof Error ? e.message : 'unknown error');
|
|
3757
3758
|
return { id: 'v37', item: ITEM, category: CATEGORY, status: 'WARN', detail: `/DESIGN.md fetched but lint failed: ${msg}. The file may use a format version the linter doesn't support yet.` };
|
|
3758
3759
|
}
|
|
3759
3760
|
}
|
|
3761
|
+
// ── Error text in a result, shared by both engine copies ───────────────────
|
|
3762
|
+
// A caught error's message carries the file system of the machine that ran
|
|
3763
|
+
// the engine: Node's "Cannot find package '@google/design.md' imported from
|
|
3764
|
+
// <path>" gives the full path of the npm cache the CLI ran from, under the
|
|
3765
|
+
// Users folder of the account that ran it, and a result is read by people
|
|
3766
|
+
// other than that account. Every check detail passes through
|
|
3767
|
+
// sanitizeErrorText before it is returned. It replaces absolute paths (a
|
|
3768
|
+
// drive letter, a UNC share, a POSIX home, temp or system root), file:// URLs
|
|
3769
|
+
// and npm cache segments, and keeps the clause that says what failed
|
|
3770
|
+
// ("Cannot find package '@google/design.md'"). A path segment may hold spaces
|
|
3771
|
+
// (an account name often does); the last one may not, so the sentence after
|
|
3772
|
+
// a path survives, and trailing punctuation is kept.
|
|
3773
|
+
function sanitizeErrorText(text) {
|
|
3774
|
+
const keep = (label) => (m) => `${label}${/[.,;:!?)]+$/.exec(m)?.[0] ?? ''}`;
|
|
3775
|
+
return text
|
|
3776
|
+
.replace(/\bfile:\/\/[^\s'"<>`|]*/gi, keep('a local file'))
|
|
3777
|
+
.replace(/\\\\[^\\\s'"<>`|]+\\(?:[^\\\r\n'"<>`|*?]+\\)*[^\\\s'"<>`|*?]*/g, keep('a local path'))
|
|
3778
|
+
.replace(/(?<![\w\\/])[A-Za-z]:([\\/])(?:[^\\/\r\n'"<>`|*?]+\1)*[^\\/\s'"<>`|*?]*/g, keep('a local path'))
|
|
3779
|
+
.replace(/(^|[\s'"`(=,:[])\/(?:home|Users|root|tmp|var|private|opt|usr|srv|mnt|Volumes|Library|app|vercel|workspace|workspaces|github|runner|nix|snap)(?:\/[^/\r\n'"<>`|]+(?=\/))*\/[^/\s'"<>`|]+/g, (m, lead) => `${lead}${keep('a local path')(m.slice(lead.length))}`)
|
|
3780
|
+
.replace(/[^\s'"<>`|]*(?:npm-cache|[\\/]_npx[\\/]|[\\/]\.npm[\\/])[^\s'"<>`|]*/gi, keep('the npm cache'));
|
|
3781
|
+
}
|
|
3782
|
+
/** The checks with every detail passed through sanitizeErrorText. */
|
|
3783
|
+
function sanitizeCheckDetails(checks) {
|
|
3784
|
+
return checks.map((c) => (typeof c.detail === 'string' ? { ...c, detail: sanitizeErrorText(c.detail) } : c));
|
|
3785
|
+
}
|
|
3760
3786
|
// ── Score arithmetic, shared by both engine copies ─────────────────────────
|
|
3761
3787
|
// Everything between the check verdicts and the grade: category weights, the
|
|
3762
3788
|
// weighted score, the slop deduction, the originality lift, the per-category
|
|
@@ -4082,7 +4108,7 @@ export async function scoreFromParts(input) {
|
|
|
4082
4108
|
detail: 'not probed: offline fixture run (no network); excluded from the score',
|
|
4083
4109
|
}
|
|
4084
4110
|
: await checkDesignMdSpec(targetUrl));
|
|
4085
|
-
checks = applyScopeFilter(checks, effectiveScope);
|
|
4111
|
+
checks = sanitizeCheckDetails(applyScopeFilter(checks, effectiveScope));
|
|
4086
4112
|
const pass = checks.filter((c) => c.status === 'PASS').length;
|
|
4087
4113
|
const fail = checks.filter((c) => c.status === 'FAIL').length;
|
|
4088
4114
|
const warn = checks.filter((c) => c.status === 'WARN').length;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@designesy/score",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"description": "Standalone 44-check design-contract scoring engine: fetches a URL, extracts CSS + tokens, and runs all checks locally.
|
|
3
|
+
"version": "0.7.1",
|
|
4
|
+
"description": "Standalone 44-check design-contract scoring engine: fetches a URL, extracts CSS + tokens, and runs all checks locally. No required dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Designesy <hello@designesy.org>",
|
|
7
7
|
"homepage": "https://www.designesy.org/score",
|
|
@@ -43,6 +43,9 @@
|
|
|
43
43
|
"engines": {
|
|
44
44
|
"node": ">=18.0.0"
|
|
45
45
|
},
|
|
46
|
+
"optionalDependencies": {
|
|
47
|
+
"@google/design.md": "0.4.0"
|
|
48
|
+
},
|
|
46
49
|
"devDependencies": {
|
|
47
50
|
"@types/node": "^26.2.0",
|
|
48
51
|
"typescript": "^5.7.0"
|