asset-doctor 0.1.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/LICENSE +21 -0
- package/README.md +133 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +157 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +8 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +62 -0
- package/dist/manifest.js.map +1 -0
- package/dist/scan.d.ts +13 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +0 -0
- package/dist/scan.js.map +1 -0
- package/dist/types.d.ts +52 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +16 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +95 -0
- package/dist/util.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 STkangyh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# asset-doctor ๐ฉบ
|
|
2
|
+
|
|
3
|
+
[](https://github.com/STkangyh/asset-doctor/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/asset-doctor)
|
|
5
|
+
|
|
6
|
+
**Health checks for your `public/` folder โ catch runtime 404s before your users do.**
|
|
7
|
+
|
|
8
|
+
Your bundler verifies every `import`. **Nobody verifies your string asset paths.**
|
|
9
|
+
A typo in `"/img/hero.png"` builds fine, deploys fine, and 404s in production.
|
|
10
|
+
Meanwhile dead files pile up in `public/` and a 20 MB SVG ships unnoticed.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npx asset-doctor check --max-size 500
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
public/ 101 assets ยท scanned 237 files ยท 97 referenced
|
|
18
|
+
โ missing 4 reference(s) point to files that don't exist
|
|
19
|
+
/img/hero@2x.png (src/components/Hero.tsx:12)
|
|
20
|
+
/lottie/loading.json (src/hooks/useAnimations.ts:8)
|
|
21
|
+
โ oversize 2 file(s) exceed 500 KB
|
|
22
|
+
/img/background.svg (15.0 MB)
|
|
23
|
+
โ orphans 4 file(s) (15.6 MB) never referenced โ review before deleting
|
|
24
|
+
โน dynamic 14 template-string reference(s) couldn't be verified
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Exits `1` on missing or oversize files โ drop it straight into CI.
|
|
28
|
+
|
|
29
|
+
## Why
|
|
30
|
+
|
|
31
|
+
Real result from the first project this ran on: **10 broken asset references**
|
|
32
|
+
(code fetching `.json` files that had been replaced by `.lottie` versions โ
|
|
33
|
+
silent runtime 404s), a **20 MB SVG** shipping to every visitor, and 15 MB of
|
|
34
|
+
orphaned files. All invisible to the bundler, the type checker, and code review.
|
|
35
|
+
|
|
36
|
+
## What it checks
|
|
37
|
+
|
|
38
|
+
| Check | What it catches |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| โ **missing** | Root-absolute references (`"/img/x.png"`) to files that don't exist โ runtime 404s. Found in JS/TS/JSX, CSS, HTML, Markdown, and even `site.webmanifest` icons. |
|
|
41
|
+
| โ **oversize** | Public files over `--max-size` KB โ your asset weight budget, enforced in CI. |
|
|
42
|
+
| โ **orphans** | Files in `public/` that no scanned file references. Conventional files (`favicon*`, `robots.txt`, `sitemap*.xml`, `*.webmanifest`, `.well-known/**`, โฆ) are exempt by default. |
|
|
43
|
+
|
|
44
|
+
## Typed asset manifest
|
|
45
|
+
|
|
46
|
+
Stop hand-maintaining an `assets.ts` full of string paths. Generate one:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx asset-doctor manifest -o src/assets.gen.ts
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// AUTO-GENERATED by asset-doctor โ do not edit.
|
|
54
|
+
export const assets = {
|
|
55
|
+
img: {
|
|
56
|
+
logo: "/img/logo.png",
|
|
57
|
+
heroImage2x: "/img/hero-image_2x.png",
|
|
58
|
+
},
|
|
59
|
+
} as const;
|
|
60
|
+
|
|
61
|
+
export type AssetPath = (typeof assetList)[number];
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Now `assets.img.logo` autocompletes, and a renamed file becomes a **compile
|
|
65
|
+
error** instead of a production 404. (Generated files are automatically
|
|
66
|
+
excluded from reference scanning, so the manifest never masks real orphans.)
|
|
67
|
+
|
|
68
|
+
## Versus existing tools
|
|
69
|
+
|
|
70
|
+
| | asset-doctor | knip / deadfile | assetdrain |
|
|
71
|
+
| --- | :---: | :---: | :---: |
|
|
72
|
+
| Broken references (404s) | โ
| โ | โ |
|
|
73
|
+
| Orphaned public assets | โ
| โ module graph only โ string paths are invisible to it | โ
|
|
|
74
|
+
| Size budget for CI | โ
| โ | โ |
|
|
75
|
+
| Typed manifest generator | โ
| โ | โ |
|
|
76
|
+
| Runtime dependencies | **0** | โ | โ |
|
|
77
|
+
|
|
78
|
+
Module-graph tools (knip, deadfile) are great at unused *code*, but `public/`
|
|
79
|
+
assets referenced by URL string never enter the module graph โ they can't see
|
|
80
|
+
them. assetdrain cleans unused assets but doesn't catch broken references,
|
|
81
|
+
which is where the actual bugs are.
|
|
82
|
+
|
|
83
|
+
## Usage
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Full health check (CI-friendly: exits 1 on missing/oversize)
|
|
87
|
+
asset-doctor check --max-size 500
|
|
88
|
+
|
|
89
|
+
# Treat orphans as errors too
|
|
90
|
+
asset-doctor check --fail-orphans
|
|
91
|
+
|
|
92
|
+
# Custom public dir, extra orphan exemptions, JSON output
|
|
93
|
+
asset-doctor check --public static --exempt "og/**" --json
|
|
94
|
+
|
|
95
|
+
# Generate the typed manifest
|
|
96
|
+
asset-doctor manifest -o src/assets.gen.ts
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### GitHub Action
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
- uses: STkangyh/asset-doctor@v1
|
|
103
|
+
with:
|
|
104
|
+
max-size: 500
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Library
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { scan, generateManifest, collectAssets } from "asset-doctor";
|
|
111
|
+
|
|
112
|
+
const report = scan({ root: process.cwd(), maxSizeKb: 500 });
|
|
113
|
+
if (report.missing.length > 0) process.exit(1);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Honest limitations
|
|
117
|
+
|
|
118
|
+
- Matching is **exact string matching** (after stripping `?query`/`#hash`).
|
|
119
|
+
Paths built with template interpolation can't be verified โ they're counted
|
|
120
|
+
and reported as `dynamic`, never guessed at.
|
|
121
|
+
- Because of dynamic paths, **orphans are warnings by default**. Review before
|
|
122
|
+
deleting; use `--fail-orphans` once you trust the result.
|
|
123
|
+
- A root-absolute string with an asset extension (`"/foo/bar.json"`) is assumed
|
|
124
|
+
to target `public/`. If it's actually an API route, add it to `--exempt`.
|
|
125
|
+
|
|
126
|
+
## Sister project
|
|
127
|
+
|
|
128
|
+
๐ฉบ [lottie-doctor](https://github.com/STkangyh/lottie-doctor) โ diagnose and
|
|
129
|
+
repair broken Lottie files (garbled text, size bloat).
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
import { generateManifest } from "./manifest.js";
|
|
6
|
+
import { collectAssets, scan } from "./scan.js";
|
|
7
|
+
import { GENERATED_MARKER } from "./util.js";
|
|
8
|
+
const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
9
|
+
const paint = (code) => (s) => useColor ? `\x1b[${code}m${s}\x1b[0m` : s;
|
|
10
|
+
const c = {
|
|
11
|
+
red: paint("31"),
|
|
12
|
+
green: paint("32"),
|
|
13
|
+
yellow: paint("33"),
|
|
14
|
+
blue: paint("36"),
|
|
15
|
+
dim: paint("2"),
|
|
16
|
+
bold: paint("1"),
|
|
17
|
+
};
|
|
18
|
+
function fmtBytes(n) {
|
|
19
|
+
if (n >= 1024 * 1024)
|
|
20
|
+
return `${(n / 1024 / 1024).toFixed(1)} MB`;
|
|
21
|
+
if (n >= 1024)
|
|
22
|
+
return `${(n / 1024).toFixed(1)} KB`;
|
|
23
|
+
return `${n} B`;
|
|
24
|
+
}
|
|
25
|
+
const HELP = `asset-doctor โ health checks for your public/ assets
|
|
26
|
+
|
|
27
|
+
Usage:
|
|
28
|
+
asset-doctor check [--root <dir>] [--public <dir>] [--max-size <KB>]
|
|
29
|
+
[--fail-orphans] [--exempt <glob>]... [--json]
|
|
30
|
+
asset-doctor manifest [-o <file>] [--root <dir>] [--public <dir>]
|
|
31
|
+
|
|
32
|
+
check Cross-reference public/ against your source code.
|
|
33
|
+
โ missing references to files that don't exist (runtime 404s)
|
|
34
|
+
โ orphans files in public/ that nothing references
|
|
35
|
+
โ oversize files exceeding --max-size
|
|
36
|
+
Exits 1 on missing refs or oversize files (CI-friendly).
|
|
37
|
+
manifest Generate a typed TS manifest of every public asset, so a typo in
|
|
38
|
+
an asset path becomes a compile error.
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
--root <dir> Project root (default: current directory)
|
|
42
|
+
--public <dir> Public directory name (default: public)
|
|
43
|
+
--max-size <KB> Flag public files larger than this
|
|
44
|
+
--fail-orphans Exit 1 when orphans are found (default: warn only)
|
|
45
|
+
--exempt <glob> Extra orphan exemptions (repeatable)
|
|
46
|
+
--json Machine-readable output
|
|
47
|
+
-o, --output <file> Manifest output path (default: src/assets.gen.ts)
|
|
48
|
+
-h, --help Show this help
|
|
49
|
+
`;
|
|
50
|
+
function cmdCheck(o) {
|
|
51
|
+
const r = scan({
|
|
52
|
+
root: o.root,
|
|
53
|
+
publicDir: o.publicDir,
|
|
54
|
+
maxSizeKb: o.maxSize,
|
|
55
|
+
exemptOrphans: o.exempt,
|
|
56
|
+
});
|
|
57
|
+
const failed = r.missing.length > 0 ||
|
|
58
|
+
r.oversize.length > 0 ||
|
|
59
|
+
(o.failOrphans && r.orphans.length > 0);
|
|
60
|
+
if (o.json) {
|
|
61
|
+
console.log(JSON.stringify(r, null, 2));
|
|
62
|
+
return failed ? 1 : 0;
|
|
63
|
+
}
|
|
64
|
+
console.log(`${c.bold(o.publicDir + "/")} ${r.publicFiles} assets ยท scanned ${r.readableFiles} files ยท ${r.referencedCount} referenced`);
|
|
65
|
+
if (r.missing.length > 0) {
|
|
66
|
+
console.log(` ${c.red("โ missing")} ${r.missing.length} reference(s) point to files that don't exist`);
|
|
67
|
+
for (const m of r.missing.slice(0, 8)) {
|
|
68
|
+
console.log(` ${m.ref} ${c.dim(`(${m.file}:${m.line})`)}`);
|
|
69
|
+
}
|
|
70
|
+
if (r.missing.length > 8)
|
|
71
|
+
console.log(c.dim(` โฆ and ${r.missing.length - 8} more (--json for all)`));
|
|
72
|
+
}
|
|
73
|
+
if (r.oversize.length > 0) {
|
|
74
|
+
console.log(` ${c.red("โ oversize")} ${r.oversize.length} file(s) exceed ${o.maxSize} KB`);
|
|
75
|
+
for (const f of r.oversize.slice(0, 8)) {
|
|
76
|
+
console.log(` ${f.path} ${c.dim(`(${fmtBytes(f.sizeBytes)})`)}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (r.orphans.length > 0) {
|
|
80
|
+
console.log(` ${c.yellow("โ orphans")} ${r.orphans.length} file(s) (${fmtBytes(r.orphanBytes)}) never referenced โ review before deleting`);
|
|
81
|
+
for (const f of r.orphans.slice(0, 8)) {
|
|
82
|
+
console.log(` ${f.path} ${c.dim(`(${fmtBytes(f.sizeBytes)})`)}`);
|
|
83
|
+
}
|
|
84
|
+
if (r.orphans.length > 8)
|
|
85
|
+
console.log(c.dim(` โฆ and ${r.orphans.length - 8} more (--json for all)`));
|
|
86
|
+
}
|
|
87
|
+
if (r.dynamicRefs > 0) {
|
|
88
|
+
console.log(` ${c.blue("โน dynamic")} ${r.dynamicRefs} template-string reference(s) couldn't be verified`);
|
|
89
|
+
}
|
|
90
|
+
if (!failed && r.orphans.length === 0) {
|
|
91
|
+
console.log(` ${c.green("โ healthy")}`);
|
|
92
|
+
}
|
|
93
|
+
return failed ? 1 : 0;
|
|
94
|
+
}
|
|
95
|
+
function cmdManifest(o) {
|
|
96
|
+
const assets = collectAssets(o.root, o.publicDir);
|
|
97
|
+
if (assets.size === 0) {
|
|
98
|
+
console.error(c.red(`error: no assets found under ${o.publicDir}/ (root: ${o.root})`));
|
|
99
|
+
return 2;
|
|
100
|
+
}
|
|
101
|
+
if (existsSync(o.output)) {
|
|
102
|
+
const head = readFileSync(o.output, "utf8").slice(0, 300);
|
|
103
|
+
if (!head.includes(GENERATED_MARKER)) {
|
|
104
|
+
console.error(c.red(`error: ${o.output} exists and was not generated by asset-doctor โ refusing to overwrite`));
|
|
105
|
+
return 2;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
mkdirSync(dirname(o.output), { recursive: true });
|
|
109
|
+
writeFileSync(o.output, generateManifest(assets.keys()));
|
|
110
|
+
console.log(`${c.green("โ")} wrote ${c.bold(o.output)} (${assets.size} assets)`);
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
function main() {
|
|
114
|
+
const { values, positionals } = parseArgs({
|
|
115
|
+
allowPositionals: true,
|
|
116
|
+
options: {
|
|
117
|
+
root: { type: "string" },
|
|
118
|
+
public: { type: "string" },
|
|
119
|
+
"max-size": { type: "string" },
|
|
120
|
+
"fail-orphans": { type: "boolean", default: false },
|
|
121
|
+
exempt: { type: "string", multiple: true },
|
|
122
|
+
json: { type: "boolean", default: false },
|
|
123
|
+
output: { type: "string", short: "o" },
|
|
124
|
+
help: { type: "boolean", short: "h", default: false },
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
if (values.help || positionals.length === 0) {
|
|
128
|
+
console.log(HELP);
|
|
129
|
+
return values.help ? 0 : 1;
|
|
130
|
+
}
|
|
131
|
+
const root = values.root ?? process.cwd();
|
|
132
|
+
const publicDir = values.public ?? "public";
|
|
133
|
+
const command = positionals[0];
|
|
134
|
+
switch (command) {
|
|
135
|
+
case "check":
|
|
136
|
+
return cmdCheck({
|
|
137
|
+
root,
|
|
138
|
+
publicDir,
|
|
139
|
+
maxSize: values["max-size"] != null ? Number(values["max-size"]) : null,
|
|
140
|
+
failOrphans: values["fail-orphans"],
|
|
141
|
+
exempt: values.exempt ?? [],
|
|
142
|
+
json: values.json,
|
|
143
|
+
});
|
|
144
|
+
case "manifest":
|
|
145
|
+
return cmdManifest({
|
|
146
|
+
root,
|
|
147
|
+
publicDir,
|
|
148
|
+
output: values.output ?? "src/assets.gen.ts",
|
|
149
|
+
});
|
|
150
|
+
default:
|
|
151
|
+
console.error(c.red(`unknown command: ${command}`));
|
|
152
|
+
console.log(HELP);
|
|
153
|
+
return 2;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
process.exit(main());
|
|
157
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EACV,UAAU,EACV,WAAW,EACX,aAAa,EACb,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a typed TypeScript manifest module from a list of public web paths
|
|
3
|
+
* (as produced by {@link collectAssets}). The result is a nested `assets`
|
|
4
|
+
* object mirroring the directory structure, plus a flat `assetList` and an
|
|
5
|
+
* `AssetPath` union type โ so a typo in an asset path is a compile error.
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateManifest(webPaths: Iterable<string>): string;
|
|
8
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AA4BA;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,CA+BnE"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { GENERATED_MARKER, IDENT_RE, camelCase } from "./util.js";
|
|
2
|
+
function keyFor(node, fileName) {
|
|
3
|
+
const stem = fileName.replace(/\.[^.]+$/, "");
|
|
4
|
+
let key = camelCase(stem) || stem;
|
|
5
|
+
if (!(key in node))
|
|
6
|
+
return key;
|
|
7
|
+
key = camelCase(fileName) || fileName; // disambiguate by extension
|
|
8
|
+
let i = 2;
|
|
9
|
+
let candidate = key;
|
|
10
|
+
while (candidate in node)
|
|
11
|
+
candidate = key + i++;
|
|
12
|
+
return candidate;
|
|
13
|
+
}
|
|
14
|
+
function serialize(node, depth) {
|
|
15
|
+
const pad = " ".repeat(depth);
|
|
16
|
+
const keys = Object.keys(node).sort();
|
|
17
|
+
const lines = keys.map((k) => {
|
|
18
|
+
const v = node[k];
|
|
19
|
+
const key = IDENT_RE.test(k) ? k : JSON.stringify(k);
|
|
20
|
+
return typeof v === "string"
|
|
21
|
+
? `${pad}${key}: ${JSON.stringify(v)},`
|
|
22
|
+
: `${pad}${key}: ${serialize(v, depth + 1)},`;
|
|
23
|
+
});
|
|
24
|
+
return "{\n" + lines.join("\n") + "\n" + " ".repeat(depth - 1) + "}";
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Generate a typed TypeScript manifest module from a list of public web paths
|
|
28
|
+
* (as produced by {@link collectAssets}). The result is a nested `assets`
|
|
29
|
+
* object mirroring the directory structure, plus a flat `assetList` and an
|
|
30
|
+
* `AssetPath` union type โ so a typo in an asset path is a compile error.
|
|
31
|
+
*/
|
|
32
|
+
export function generateManifest(webPaths) {
|
|
33
|
+
const sorted = [...webPaths].sort();
|
|
34
|
+
const root = {};
|
|
35
|
+
for (const p of sorted) {
|
|
36
|
+
const segs = p.slice(1).split("/");
|
|
37
|
+
const file = segs.pop();
|
|
38
|
+
let node = root;
|
|
39
|
+
for (const dir of segs) {
|
|
40
|
+
let key = camelCase(dir) || dir;
|
|
41
|
+
if (typeof node[key] === "string")
|
|
42
|
+
key += "Dir";
|
|
43
|
+
node = (node[key] ??= {});
|
|
44
|
+
}
|
|
45
|
+
node[keyFor(node, file)] = p;
|
|
46
|
+
}
|
|
47
|
+
const list = sorted.map((p) => ` ${JSON.stringify(p)},`).join("\n");
|
|
48
|
+
return [
|
|
49
|
+
`// ${GENERATED_MARKER} โ do not edit.`,
|
|
50
|
+
`// Regenerate with: npx asset-doctor manifest`,
|
|
51
|
+
``,
|
|
52
|
+
`export const assets = ${serialize(root, 1)} as const;`,
|
|
53
|
+
``,
|
|
54
|
+
`export const assetList = [`,
|
|
55
|
+
list,
|
|
56
|
+
`] as const;`,
|
|
57
|
+
``,
|
|
58
|
+
`export type AssetPath = (typeof assetList)[number];`,
|
|
59
|
+
``,
|
|
60
|
+
].join("\n");
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|
package/dist/scan.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ScanOptions, ScanReport } from "./types.js";
|
|
2
|
+
/** List public assets as web paths (`/img/logo.png`) with their sizes. */
|
|
3
|
+
export declare function collectAssets(root: string, publicDir?: string): Map<string, number>;
|
|
4
|
+
/**
|
|
5
|
+
* Cross-check the public directory against every reference in the codebase.
|
|
6
|
+
*
|
|
7
|
+
* Finds: references to assets that don't exist (runtime 404s), assets nothing
|
|
8
|
+
* references (orphans), and assets over the size budget. String matching is
|
|
9
|
+
* exact after stripping `?query`/`#hash`; root-absolute references built with
|
|
10
|
+
* template interpolation are counted as `dynamicRefs` and never flagged.
|
|
11
|
+
*/
|
|
12
|
+
export declare function scan(options?: ScanOptions): ScanReport;
|
|
13
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAIV,WAAW,EACX,UAAU,EACX,MAAM,YAAY,CAAC;AAmDpB,0EAA0E;AAC1E,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,SAAW,GACnB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAYrB;AAED;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,UAAU,CAwG1D"}
|
package/dist/scan.js
ADDED
|
Binary file
|
package/dist/scan.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Options for {@link scan}. */
|
|
2
|
+
export interface ScanOptions {
|
|
3
|
+
/** Project root to scan. Default: `process.cwd()`. */
|
|
4
|
+
root?: string;
|
|
5
|
+
/** Static-assets directory name, relative to root. Default: `"public"`. */
|
|
6
|
+
publicDir?: string;
|
|
7
|
+
/** Flag public files larger than this many KB. `null` disables. Default: `null`. */
|
|
8
|
+
maxSizeKb?: number | null;
|
|
9
|
+
/**
|
|
10
|
+
* Extra glob patterns (matched against the public-relative path and the
|
|
11
|
+
* basename) exempted from the orphan check, on top of the built-in
|
|
12
|
+
* conventions (favicon*, robots.txt, sitemap*.xml, *.webmanifest, โฆ).
|
|
13
|
+
*/
|
|
14
|
+
exemptOrphans?: string[];
|
|
15
|
+
}
|
|
16
|
+
/** A reference in source code to a public asset that does not exist. */
|
|
17
|
+
export interface MissingRef {
|
|
18
|
+
/** The referenced web path, e.g. `/img/hero.png`. */
|
|
19
|
+
ref: string;
|
|
20
|
+
/** Source file containing the reference, relative to root. */
|
|
21
|
+
file: string;
|
|
22
|
+
/** 1-based line number of the reference. */
|
|
23
|
+
line: number;
|
|
24
|
+
}
|
|
25
|
+
/** A public asset that no scanned file references. */
|
|
26
|
+
export interface OrphanAsset {
|
|
27
|
+
/** Web path of the asset, e.g. `/img/old-banner.png`. */
|
|
28
|
+
path: string;
|
|
29
|
+
sizeBytes: number;
|
|
30
|
+
}
|
|
31
|
+
/** A public asset exceeding the size budget. */
|
|
32
|
+
export interface OversizeAsset {
|
|
33
|
+
path: string;
|
|
34
|
+
sizeBytes: number;
|
|
35
|
+
}
|
|
36
|
+
/** The result of {@link scan}. */
|
|
37
|
+
export interface ScanReport {
|
|
38
|
+
/** Number of files found under the public directory. */
|
|
39
|
+
publicFiles: number;
|
|
40
|
+
/** Number of source/text files whose contents were scanned for references. */
|
|
41
|
+
readableFiles: number;
|
|
42
|
+
/** Number of distinct public assets referenced somewhere. */
|
|
43
|
+
referencedCount: number;
|
|
44
|
+
/** Root-absolute references built with template interpolation โ unverifiable. */
|
|
45
|
+
dynamicRefs: number;
|
|
46
|
+
missing: MissingRef[];
|
|
47
|
+
orphans: OrphanAsset[];
|
|
48
|
+
oversize: OversizeAsset[];
|
|
49
|
+
/** Total size of all orphaned assets, in bytes. */
|
|
50
|
+
orphanBytes: number;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,wEAAwE;AACxE,MAAM,WAAW,UAAU;IACzB,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,sDAAsD;AACtD,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,gDAAgD;AAChD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,kCAAkC;AAClC,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,aAAa,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,eAAe,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/dist/util.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** First-line marker that identifies files generated by asset-doctor. */
|
|
2
|
+
export declare const GENERATED_MARKER = "AUTO-GENERATED by asset-doctor";
|
|
3
|
+
/**
|
|
4
|
+
* Orphan-check exemptions for files browsers and crawlers fetch by
|
|
5
|
+
* convention, without any reference appearing in source code.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_ORPHAN_EXEMPT: string[];
|
|
8
|
+
/** Recursively list all regular files under `dir` (absolute paths). */
|
|
9
|
+
export declare function walk(dir: string): string[];
|
|
10
|
+
/** Minimal glob โ RegExp: `**` crosses slashes, `*` does not, `?` is one char. */
|
|
11
|
+
export declare function globToRegExp(glob: string): RegExp;
|
|
12
|
+
/** Valid bare JS identifier (no quoting needed as an object key). */
|
|
13
|
+
export declare const IDENT_RE: RegExp;
|
|
14
|
+
/** `"hero_image-2x"` โ `"heroImage2x"`. */
|
|
15
|
+
export declare function camelCase(s: string): string;
|
|
16
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAGA,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,mCAAmC,CAAC;AAcjE;;;GAGG;AACH,eAAO,MAAM,qBAAqB,UAWjC,CAAC;AAEF,uEAAuE;AACvE,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAoB1C;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoBjD;AAED,qEAAqE;AACrE,eAAO,MAAM,QAAQ,QAA+B,CAAC;AAErD,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAS3C"}
|
package/dist/util.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { readdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/** First-line marker that identifies files generated by asset-doctor. */
|
|
4
|
+
export const GENERATED_MARKER = "AUTO-GENERATED by asset-doctor";
|
|
5
|
+
/** Directories never worth scanning. */
|
|
6
|
+
const SKIP_DIRS = new Set([
|
|
7
|
+
"node_modules",
|
|
8
|
+
"dist",
|
|
9
|
+
"build",
|
|
10
|
+
"out",
|
|
11
|
+
"coverage",
|
|
12
|
+
"vendor",
|
|
13
|
+
]);
|
|
14
|
+
const JUNK_FILES = new Set([".DS_Store", "Thumbs.db", "desktop.ini", ".gitkeep"]);
|
|
15
|
+
/**
|
|
16
|
+
* Orphan-check exemptions for files browsers and crawlers fetch by
|
|
17
|
+
* convention, without any reference appearing in source code.
|
|
18
|
+
*/
|
|
19
|
+
export const DEFAULT_ORPHAN_EXEMPT = [
|
|
20
|
+
"robots.txt",
|
|
21
|
+
"sitemap*.xml",
|
|
22
|
+
"favicon*",
|
|
23
|
+
"apple-touch-icon*",
|
|
24
|
+
"*.webmanifest",
|
|
25
|
+
"manifest.json",
|
|
26
|
+
"browserconfig.xml",
|
|
27
|
+
"humans.txt",
|
|
28
|
+
"ads.txt",
|
|
29
|
+
".well-known/**",
|
|
30
|
+
];
|
|
31
|
+
/** Recursively list all regular files under `dir` (absolute paths). */
|
|
32
|
+
export function walk(dir) {
|
|
33
|
+
const out = [];
|
|
34
|
+
let entries;
|
|
35
|
+
try {
|
|
36
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
for (const e of entries) {
|
|
42
|
+
if (e.isDirectory()) {
|
|
43
|
+
if (SKIP_DIRS.has(e.name))
|
|
44
|
+
continue;
|
|
45
|
+
// skip dot-directories (.git, .next, .vercel, โฆ) except .well-known,
|
|
46
|
+
// which legitimately lives inside public/
|
|
47
|
+
if (e.name.startsWith(".") && e.name !== ".well-known")
|
|
48
|
+
continue;
|
|
49
|
+
out.push(...walk(join(dir, e.name)));
|
|
50
|
+
}
|
|
51
|
+
else if (e.isFile()) {
|
|
52
|
+
if (!JUNK_FILES.has(e.name))
|
|
53
|
+
out.push(join(dir, e.name));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
/** Minimal glob โ RegExp: `**` crosses slashes, `*` does not, `?` is one char. */
|
|
59
|
+
export function globToRegExp(glob) {
|
|
60
|
+
const g = glob.replace(/^\//, "");
|
|
61
|
+
let re = "";
|
|
62
|
+
for (let i = 0; i < g.length; i++) {
|
|
63
|
+
const ch = g[i];
|
|
64
|
+
if (ch === "*") {
|
|
65
|
+
if (g[i + 1] === "*") {
|
|
66
|
+
re += ".*";
|
|
67
|
+
i++;
|
|
68
|
+
if (g[i + 1] === "/")
|
|
69
|
+
i++;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
re += "[^/]*";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (ch === "?") {
|
|
76
|
+
re += "[^/]";
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
re += ch.replace(/[.+^${}()|[\]\\]/, "\\$&");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return new RegExp("^" + re + "$");
|
|
83
|
+
}
|
|
84
|
+
/** Valid bare JS identifier (no quoting needed as an object key). */
|
|
85
|
+
export const IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
86
|
+
/** `"hero_image-2x"` โ `"heroImage2x"`. */
|
|
87
|
+
export function camelCase(s) {
|
|
88
|
+
const parts = s.split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
89
|
+
return parts
|
|
90
|
+
.map((p, i) => i === 0
|
|
91
|
+
? p.charAt(0).toLowerCase() + p.slice(1)
|
|
92
|
+
: p.charAt(0).toUpperCase() + p.slice(1))
|
|
93
|
+
.join("");
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "asset-doctor",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Health checks for your public/ assets: find broken references (runtime 404s), orphaned files, and oversized assets โ and generate a typed asset manifest. Zero dependencies.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"asset-doctor": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc -p tsconfig.json",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"prepublishOnly": "npm run build"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"assets",
|
|
32
|
+
"public",
|
|
33
|
+
"unused",
|
|
34
|
+
"orphan",
|
|
35
|
+
"missing",
|
|
36
|
+
"404",
|
|
37
|
+
"broken-links",
|
|
38
|
+
"nextjs",
|
|
39
|
+
"vite",
|
|
40
|
+
"cli",
|
|
41
|
+
"linter",
|
|
42
|
+
"manifest",
|
|
43
|
+
"typescript"
|
|
44
|
+
],
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"author": "STkangyh",
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/STkangyh/asset-doctor.git"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/STkangyh/asset-doctor#readme",
|
|
52
|
+
"bugs": "https://github.com/STkangyh/asset-doctor/issues",
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/node": "^22",
|
|
55
|
+
"typescript": "^5",
|
|
56
|
+
"vitest": "^3"
|
|
57
|
+
}
|
|
58
|
+
}
|