-
-
Notifications
You must be signed in to change notification settings - Fork 144
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(examples): add package-stats charting example
- Loading branch information
1 parent
27438f9
commit bac59db
Showing
8 changed files
with
358 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.cache | ||
out | ||
node_modules | ||
yarn.lock | ||
*.js | ||
*.svg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# package-stats | ||
|
||
This non-browser example generates several SVG charts of various package | ||
stats in this mono-repo. The charts will be saved in this example's | ||
directory. | ||
|
||
```bash | ||
git clone https://github.com/thi-ng/umbrella.git | ||
|
||
# first need to build the entire mono-repo | ||
# to produce necessary meta data | ||
yarn install | ||
yarn build | ||
|
||
# then run example | ||
cd umbrella/examples/module-stats | ||
yarn build | ||
``` | ||
|
||
## Authors | ||
|
||
- Karsten Schmidt | ||
|
||
## License | ||
|
||
© 2018 Karsten Schmidt // Apache Software License 2.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"name": "package-stats", | ||
"version": "0.0.1", | ||
"repository": "https://github.com/thi-ng/umbrella", | ||
"author": "Karsten Schmidt <k+npm@thi.ng>", | ||
"license": "Apache-2.0", | ||
"scripts": { | ||
"clean": "rm -rf *.js *.svg lib", | ||
"build": "yarn clean && tsc && node lib/index.js" | ||
}, | ||
"devDependencies": { | ||
"parcel-bundler": "^1.10.3", | ||
"terser": "^3.11.0", | ||
"typescript": "^3.2.2" | ||
}, | ||
"dependencies": { | ||
"@thi.ng/checks": "latest", | ||
"@thi.ng/dgraph": "latest", | ||
"@thi.ng/hiccup": "latest", | ||
"@thi.ng/hiccup-svg": "latest", | ||
"@thi.ng/math": "latest", | ||
"@thi.ng/path": "latest", | ||
"@thi.ng/strings": "latest", | ||
"@thi.ng/transducers": "latest" | ||
}, | ||
"browserslist": [ | ||
"last 3 Chrome versions" | ||
], | ||
"browser": { | ||
"process": false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { exists } from "@thi.ng/checks"; | ||
import { DGraph } from "@thi.ng/dgraph"; | ||
import { serialize } from "@thi.ng/hiccup"; | ||
import { group, text } from "@thi.ng/hiccup-svg"; | ||
import { | ||
comp, | ||
filter, | ||
map, | ||
mapcat, | ||
mapIndexed, | ||
max, | ||
pluck, | ||
push, | ||
reducer, | ||
repeat, | ||
transduce, | ||
tuples | ||
} from "@thi.ng/transducers"; | ||
import * as fs from "fs"; | ||
import { | ||
barChart, | ||
labeledTickY, | ||
labeledTickX, | ||
} from "./viz"; | ||
|
||
const BASE_DIR = "../../packages/"; | ||
|
||
const packages = transduce( | ||
comp( | ||
map((f) => BASE_DIR + f), | ||
filter((f) => fs.statSync(f).isDirectory()), | ||
map((f) => { try { return fs.readFileSync(f + "/package.json"); } catch (_) { } }), | ||
filter(exists), | ||
map((p) => JSON.parse(p.toString())), | ||
map((p) => ({ | ||
id: p.name, | ||
v: p.version, | ||
deps: p.dependencies ? Object.keys(p.dependencies) : [] | ||
})) | ||
), | ||
push(), | ||
fs.readdirSync(BASE_DIR) | ||
); | ||
|
||
const graph = transduce( | ||
mapcat((p: any) => tuples(repeat(p.id), p.deps)), | ||
reducer(() => new DGraph(), (g, [p, d]) => g.addDependency(p, d)), | ||
packages | ||
); | ||
|
||
const packageDeps = packages | ||
.map((p) => [p.id, graph.transitiveDependents(p.id).size]) | ||
.sort((a, b) => b[1] - a[1]); | ||
|
||
const maxDeps = transduce(pluck(1), max(), packageDeps); | ||
|
||
fs.writeFileSync( | ||
`package-deps.svg`, | ||
serialize( | ||
[barChart, | ||
{ | ||
attribs: { | ||
width: 1024, | ||
height: 260, | ||
"font-size": "10px", | ||
"font-family": "Iosevka-Term-Light, Menlo, sans-serif" | ||
}, | ||
x: { | ||
axis: [80, 1010, 170], | ||
domain: [0, packageDeps.length, 1], | ||
range: [80, 1020], | ||
ticks: [...map((x) => x[0].substr(8), packageDeps)], | ||
label: labeledTickX | ||
}, | ||
y: { | ||
axis: [170, 10, 65], | ||
domain: [0, maxDeps, 10], | ||
range: [160, 20], | ||
label: labeledTickY(1010) | ||
}, | ||
axis: "#666", | ||
fill: "#0cc" | ||
}, | ||
mapIndexed((i, m) => [i, m[1]], packageDeps), | ||
group({ "font-size": "20px", "text-anchor": "middle" }, | ||
text([592, 28], "@thi.ng/umbrella internal re-use"), | ||
text([592, 56], "(transitive dependents)"), | ||
) | ||
] | ||
) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import "./dep-chart"; | ||
import "./size-chart"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { serialize } from "@thi.ng/hiccup"; | ||
import { group, text } from "@thi.ng/hiccup-svg"; | ||
import { getter } from "@thi.ng/paths"; | ||
import { bytes } from "@thi.ng/strings"; | ||
import { | ||
comp, | ||
filter, | ||
map, | ||
mapcat, | ||
mapIndexed, | ||
max, | ||
push, | ||
transduce | ||
} from "@thi.ng/transducers"; | ||
import * as fs from "fs"; | ||
import { barChart, labeledTickX, labeledTickY } from "./viz"; | ||
|
||
const BASE_DIR = "../../packages/"; | ||
|
||
const meta = transduce( | ||
comp( | ||
map((m: string) => [m, BASE_DIR + m + "/.meta/size.json"]), | ||
filter(([_, path]) => fs.existsSync(path)), | ||
map(([m, path]) => [m, JSON.parse(fs.readFileSync(path).toString())]) | ||
), | ||
push(), | ||
fs.readdirSync(BASE_DIR) | ||
); | ||
|
||
const fileSizeChart = | ||
(stats, modType, type) => { | ||
|
||
const get = getter([1, modType, type]); | ||
stats = [...stats].sort((a, b) => get(b) - get(a)); | ||
|
||
const maxSize = transduce( | ||
mapcat(([_, m]) => [m.esm[type], m.cjs[type], m.umd[type]]), | ||
max(), | ||
stats | ||
); | ||
|
||
fs.writeFileSync( | ||
`package-sizes-${modType}.svg`, | ||
serialize( | ||
[barChart, | ||
{ | ||
attribs: { | ||
width: 1024, | ||
height: 260, | ||
"font-size": "10px", | ||
"font-family": "Iosevka-Term-Light, Menlo, sans-serif" | ||
}, | ||
x: { | ||
axis: [80, 1010, 170], | ||
domain: [0, stats.length, 1], | ||
range: [80, 1020], | ||
ticks: [...map((x) => x[0], stats)], | ||
label: labeledTickX | ||
}, | ||
y: { | ||
axis: [170, 10, 65], | ||
domain: [0, maxSize, 5 * 1024], | ||
range: [160, 20], | ||
label: labeledTickY(1010, bytes) | ||
}, | ||
axis: "#666", | ||
fill: "#0cc" | ||
}, | ||
mapIndexed((i, m) => [i, get(m)], stats), | ||
group({ "font-size": "20px", "text-anchor": "middle" }, | ||
text([592, 28], `@thi.ng/umbrella package sizes (${modType.toUpperCase()})`), | ||
text([592, 56], `(minified + gzipped)`), | ||
) | ||
] | ||
) | ||
); | ||
}; | ||
|
||
fileSizeChart(meta, "esm", "gzip"); | ||
fileSizeChart(meta, "cjs", "gzip"); | ||
fileSizeChart(meta, "umd", "gzip"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { group, line, svg, text, rect } from "@thi.ng/hiccup-svg"; | ||
import { fit, fit01 } from "@thi.ng/math"; | ||
import { map, mapcat, range, normRange, mapIndexed } from "@thi.ng/transducers"; | ||
|
||
// iterator of range mapped tuples: `[mapped, orig]` | ||
const mappedRange = | ||
(from: number, to: number, step: number, start: number, end: number) => | ||
map( | ||
(n) => [fit(n, from, to, start, end), n], | ||
range(from, to, step) | ||
); | ||
|
||
const mappedTicks = | ||
(start: number, end: number, ticks: any[]) => | ||
mapIndexed( | ||
(i, x) => [fit01(i / ticks.length, start, end), x], | ||
0, | ||
ticks | ||
); | ||
|
||
// reusuable axis tick & label combo | ||
export const tick = | ||
(x1: number, y1: number, x2: number, y2: number, tx: number, ty: number, label: any) => [ | ||
line([x1, y1], [x2, y2]), | ||
text([tx, ty], label, { stroke: "none" }) | ||
]; | ||
|
||
// mapping fn for x-axis ticks | ||
const tickX = | ||
(y: number) => | ||
([x, n]: [number, any]) => | ||
tick(x, y, x, y + 10, x, y + 20, n); | ||
|
||
// mapping fn for y-axis ticks | ||
const tickY = | ||
(x: number) => | ||
([y, n]: [number, any]) => | ||
tick(x - 10, y, x, y, x - 15, y, n); | ||
|
||
export const labeledTickX = | ||
(y) => | ||
([x, n]: any[]) => [ | ||
line([x, y], [x, y + 5]), | ||
text([x, y + 15], n, { | ||
stroke: "none", | ||
"text-anchor": "end", | ||
transform: `rotate(-45 ${x} ${y + 15})` | ||
}) | ||
]; | ||
|
||
export const labeledTickY = | ||
(width, fmt = (x) => String(x)) => | ||
(x) => | ||
([y, n]: [number, any]) => [ | ||
...tick(x - 5, y, x, y, x - 10, y + 4, n > 0 ? fmt(n) : 0), | ||
n > 0 ? | ||
line([x + 20, y], [width, y], { "stroke-dasharray": "1 3" }) : | ||
null | ||
]; | ||
|
||
// x-axis with ticks as SVG group | ||
const axisX = | ||
({ axis: a, domain: d, range: r, label, ticks }) => | ||
["g", { "text-anchor": "middle" }, | ||
line([a[0], a[2]], [a[1], a[2]]), | ||
mapcat( | ||
(label || tickX)(a[2]), | ||
ticks ? | ||
mappedTicks(r[0], r[1], ticks) : | ||
mappedRange(d[0], d[1], d[2], r[0], r[1]) | ||
)]; | ||
|
||
// y-axis with ticks as SVG group | ||
const axisY = | ||
({ axis: a, domain: d, range: r, label, ticks }) => | ||
["g", { "text-anchor": "end" }, | ||
line([a[2], a[0]], [a[2], a[1]]), | ||
mapcat( | ||
(label || tickY)(a[2]), | ||
ticks ? | ||
mappedTicks(r[0], r[1], ticks) : | ||
mappedRange(d[0], d[1], d[2], r[0], r[1]) | ||
)]; | ||
|
||
// mapping fn to create a single bar from `[domainPos, value]` | ||
const bar = | ||
({ domain: xd, range: xr }, { domain: yd, range: yr }) => | ||
([xx, yy]) => { | ||
const y = fit(yy, yd[0], yd[1], yr[0], yr[1]); | ||
return rect( | ||
[fit(xx, xd[0], xd[1], xr[0], xr[1]) - 5, y], | ||
10, yr[0] - y | ||
); | ||
}; | ||
|
||
// complete bar chart component | ||
export const barChart = | ||
(_, opts, values, ...xs) => | ||
svg( | ||
opts.attribs, | ||
group({ stroke: opts.axis, fill: opts.axis }, | ||
axisX(opts.x), | ||
axisY(opts.y)), | ||
group({ fill: opts.fill }, | ||
map(bar(opts.x, opts.y), values)), | ||
...xs | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"extends": "../../tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "lib", | ||
"module": "commonjs", | ||
"target": "es6", | ||
"noUnusedLocals": false, | ||
"noUnusedParameters": false, | ||
}, | ||
"include": [ | ||
"./src/**/*.ts" | ||
] | ||
} |