tonnage 0.1.1 → 0.1.3
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 +12 -0
- package/README.md +31 -0
- package/dist/cli.mjs +25 -7
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +9 -9
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{run-P2rhqYM3.mjs → run-CZ_FO4C7.mjs} +2 -1
- package/dist/run-CZ_FO4C7.mjs.map +1 -0
- package/package.json +3 -3
- package/src/cli.ts +15 -2
- package/src/command-line.ts +24 -6
- package/src/report.ts +5 -0
- package/dist/run-P2rhqYM3.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# tonnage
|
|
2
2
|
|
|
3
|
+
## 0.1.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9866ade: Upgrade comline, pass full runtime argv, add command and config-path completion with shell installation commands, and report ignored-option warnings on stderr while preserving asynchronous config loading.
|
|
8
|
+
|
|
9
|
+
## 0.1.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 1ca268e: Link generated reports back to the tonnage repository.
|
|
14
|
+
|
|
3
15
|
## 0.1.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -31,12 +31,43 @@ Run `tonnage write` during development to update the README. Run
|
|
|
31
31
|
nonzero when the README is stale. Run `tonnage --help` to see both commands and
|
|
32
32
|
their optional config-path arguments.
|
|
33
33
|
|
|
34
|
+
Pass a config path with `tonnage check path/to/tonnage.config.ts` or
|
|
35
|
+
`tonnage write path/to/tonnage.config.ts`. Otherwise, Tonnage looks in the current
|
|
36
|
+
directory for `tonnage.config.ts`, then `tonnage.config.mjs`, then
|
|
37
|
+
`tonnage.config.js`. Config modules may use top-level `await`. Missing configs
|
|
38
|
+
are errors. Use `--` before a config path that starts with a dash.
|
|
39
|
+
|
|
40
|
+
Unknown options are ignored with warnings on stderr. Warnings do not change the
|
|
41
|
+
exit status; `check` still exits nonzero when the report is stale.
|
|
42
|
+
|
|
34
43
|
By default the tool reads `package.json`, writes `README.md`, and measures every
|
|
35
44
|
public export except `./package.json`. Paths are resolved relative to the config
|
|
36
45
|
file. Use `exports.include` or `exports.exclude` to select subpaths, recipe entry
|
|
37
46
|
files to describe realistic runtime boundaries, and `external` for non-peer
|
|
38
47
|
imports that the package intentionally leaves to its consumers.
|
|
39
48
|
|
|
49
|
+
### Shell completion
|
|
50
|
+
|
|
51
|
+
With `tonnage` available on your shell's `PATH`, install completion for your shell:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
tonnage completion install bash
|
|
55
|
+
tonnage completion install zsh
|
|
56
|
+
tonnage completion install fish
|
|
57
|
+
tonnage completion install nushell
|
|
58
|
+
tonnage completion install carapace
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Choose the integration you use. Completion suggests commands, help options, and
|
|
62
|
+
config paths without loading your config or measuring bundles. Installation
|
|
63
|
+
checks the shell's prerequisites and writes to its completion directory without
|
|
64
|
+
editing shell profiles. It reports any setup needed for your shell. If Nushell
|
|
65
|
+
already uses Carapace, install only the Carapace integration.
|
|
66
|
+
|
|
67
|
+
Run `tonnage completion bash` (or another target above) to print the integration
|
|
68
|
+
file without installing it. The `completion` command and comline's internal
|
|
69
|
+
completion protocol commands are reserved for shell integration.
|
|
70
|
+
|
|
40
71
|
## Report layout
|
|
41
72
|
|
|
42
73
|
Generated reports adapt to the measurements they contain. An exports-only or
|
package/dist/cli.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as runTonnage } from "./run-
|
|
2
|
+
import { t as runTonnage } from "./run-CZ_FO4C7.mjs";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
|
-
import { cli, help, helpOption, optional } from "comline";
|
|
6
|
+
import { cli, completionResponse, help, helpOption, logWarnings, optional } from "comline";
|
|
7
7
|
//#region src/command-line.ts
|
|
8
8
|
const ROOT_MANUAL = helpOption(`Show help for the tonnage command line.`);
|
|
9
9
|
const WRITE_MANUAL = helpOption(`Update the configured README report.`);
|
|
@@ -22,20 +22,32 @@ const tonnageCli = cli({
|
|
|
22
22
|
write: WRITE_MANUAL,
|
|
23
23
|
"write/$configPath": WRITE_MANUAL
|
|
24
24
|
},
|
|
25
|
+
positionalCompletions: {
|
|
26
|
+
"check/$configPath": { fileSystem: `files` },
|
|
27
|
+
"write/$configPath": { fileSystem: `files` }
|
|
28
|
+
},
|
|
25
29
|
discoverConfigPath: () => void 0
|
|
26
30
|
});
|
|
31
|
+
function completeTonnageCli(args) {
|
|
32
|
+
return completionResponse(tonnageCli.definition, args);
|
|
33
|
+
}
|
|
27
34
|
function parseTonnageCli(args) {
|
|
28
|
-
const { inputs } = tonnageCli(args);
|
|
29
|
-
if (inputs.case === `` || inputs.opts.help) return {
|
|
35
|
+
const { inputs, warnings } = tonnageCli(args);
|
|
36
|
+
if (inputs.case === `` || inputs.opts.help) return {
|
|
37
|
+
kind: `help`,
|
|
38
|
+
warnings
|
|
39
|
+
};
|
|
30
40
|
const mode = inputs.case === `write` || inputs.case === `write/$configPath` ? `write` : `check`;
|
|
31
41
|
const configArgument = inputs.path[1];
|
|
32
42
|
return configArgument === void 0 ? {
|
|
33
43
|
kind: `run`,
|
|
34
|
-
mode
|
|
44
|
+
mode,
|
|
45
|
+
warnings
|
|
35
46
|
} : {
|
|
36
47
|
configArgument,
|
|
37
48
|
kind: `run`,
|
|
38
|
-
mode
|
|
49
|
+
mode,
|
|
50
|
+
warnings
|
|
39
51
|
};
|
|
40
52
|
}
|
|
41
53
|
function renderTonnageCliHelp() {
|
|
@@ -49,7 +61,13 @@ const DEFAULT_CONFIG_FILES = [
|
|
|
49
61
|
`tonnage.config.js`
|
|
50
62
|
];
|
|
51
63
|
async function main() {
|
|
52
|
-
const
|
|
64
|
+
const completion = await completeTonnageCli(process.argv);
|
|
65
|
+
if (completion !== void 0) {
|
|
66
|
+
process.stdout.write(completion);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const invocation = parseTonnageCli(process.argv);
|
|
70
|
+
logWarnings(invocation.warnings);
|
|
53
71
|
if (invocation.kind === `help`) {
|
|
54
72
|
process.stdout.write(renderTonnageCliHelp());
|
|
55
73
|
return;
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/command-line.ts","../src/cli.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/command-line.ts","../src/cli.ts"],"sourcesContent":["import {\n\ttype CliWarning,\n\tcli,\n\tcompletionResponse,\n\thelp,\n\thelpOption,\n\toptional,\n} from \"comline\"\n\nimport type { TonnageMode } from \"./types.ts\"\n\nconst ROOT_MANUAL = helpOption(`Show help for the tonnage command line.`)\nconst WRITE_MANUAL = helpOption(`Update the configured README report.`)\nconst CHECK_MANUAL = helpOption(\n\t`Check that the configured README report is up to date.`,\n)\n\nconst tonnageCli = cli({\n\tcliName: `tonnage`,\n\tcliDescription: `Keep deterministic bundle size reports in README files and CI.`,\n\troutes: optional({\n\t\tcheck: optional({ $configPath: null }),\n\t\twrite: optional({ $configPath: null }),\n\t}),\n\trouteOptions: {\n\t\t\"\": ROOT_MANUAL,\n\t\tcheck: CHECK_MANUAL,\n\t\t\"check/$configPath\": CHECK_MANUAL,\n\t\twrite: WRITE_MANUAL,\n\t\t\"write/$configPath\": WRITE_MANUAL,\n\t},\n\tpositionalCompletions: {\n\t\t\"check/$configPath\": { fileSystem: `files` },\n\t\t\"write/$configPath\": { fileSystem: `files` },\n\t},\n\tdiscoverConfigPath: () => undefined,\n})\n\nexport type TonnageCliInvocation = { warnings: CliWarning[] } & (\n\t| { kind: `help` }\n\t| { configArgument?: string; kind: `run`; mode: TonnageMode }\n)\n\nexport function completeTonnageCli(\n\targs: string[],\n): Promise<string | undefined> {\n\treturn completionResponse(tonnageCli.definition, args)\n}\n\nexport function parseTonnageCli(args: string[]): TonnageCliInvocation {\n\tconst { inputs, warnings } = tonnageCli(args)\n\n\tif (inputs.case === `` || inputs.opts.help) {\n\t\treturn { kind: `help`, warnings }\n\t}\n\n\tconst mode =\n\t\tinputs.case === `write` || inputs.case === `write/$configPath`\n\t\t\t? `write`\n\t\t\t: `check`\n\tconst configArgument = inputs.path[1]\n\n\treturn configArgument === undefined\n\t\t? { kind: `run`, mode, warnings }\n\t\t: { configArgument, kind: `run`, mode, warnings }\n}\n\nexport function renderTonnageCliHelp(): string {\n\treturn help(tonnageCli.definition)\n}\n","#!/usr/bin/env node\n\nimport fs from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\n\nimport { logWarnings } from \"comline\"\n\nimport {\n\tcompleteTonnageCli,\n\tparseTonnageCli,\n\trenderTonnageCliHelp,\n} from \"./command-line.ts\"\nimport { runTonnage } from \"./run.ts\"\nimport type { TonnageConfig } from \"./types.ts\"\n\nconst DEFAULT_CONFIG_FILES = [\n\t`tonnage.config.ts`,\n\t`tonnage.config.mjs`,\n\t`tonnage.config.js`,\n]\n\nasync function main(): Promise<void> {\n\tconst completion = await completeTonnageCli(process.argv)\n\tif (completion !== undefined) {\n\t\tprocess.stdout.write(completion)\n\t\treturn\n\t}\n\n\tconst invocation = parseTonnageCli(process.argv)\n\tlogWarnings(invocation.warnings)\n\tif (invocation.kind === `help`) {\n\t\tprocess.stdout.write(renderTonnageCliHelp())\n\t\treturn\n\t}\n\n\tconst { configArgument, mode } = invocation\n\tconst configPath = await findConfig(configArgument)\n\tconst config = await loadConfig(configPath)\n\tconst result = await runTonnage(config, {\n\t\tconfigDirectory: path.dirname(configPath),\n\t\tmode,\n\t})\n\n\tif (mode === `check` && result.changed) {\n\t\tprocess.stderr.write(\n\t\t\t`${path.relative(process.cwd(), result.readmePath)} is out of date. Run tonnage write.\\n`,\n\t\t)\n\t\tprocess.exitCode = 1\n\t\treturn\n\t}\n\n\tconst readme = path.relative(process.cwd(), result.readmePath)\n\tprocess.stdout.write(\n\t\tresult.changed\n\t\t\t? `Updated ${readme}.\\n`\n\t\t\t: `${readme} is already up to date.\\n`,\n\t)\n}\n\nasync function findConfig(configArgument: string | undefined): Promise<string> {\n\tif (configArgument) {\n\t\treturn path.resolve(configArgument)\n\t}\n\n\tfor (const filename of DEFAULT_CONFIG_FILES) {\n\t\tconst candidate = path.resolve(filename)\n\t\ttry {\n\t\t\tawait fs.access(candidate)\n\t\t\treturn candidate\n\t\t} catch {\n\t\t\t// Keep looking for the next supported config filename.\n\t\t}\n\t}\n\n\tthrow new Error(\n\t\t`Could not find a tonnage config (${DEFAULT_CONFIG_FILES.join(`, `)}).`,\n\t)\n}\n\nasync function loadConfig(configPath: string): Promise<TonnageConfig> {\n\tconst imported = (await import(pathToFileURL(configPath).href)) as {\n\t\tdefault?: unknown\n\t}\n\tif (!imported.default || typeof imported.default !== `object`) {\n\t\tthrow new Error(`${configPath} must default-export a tonnage config.`)\n\t}\n\treturn imported.default\n}\n\nmain().catch((error: unknown) => {\n\tprocess.stderr.write(\n\t\t`${error instanceof Error ? error.message : String(error)}\\n`,\n\t)\n\tprocess.exitCode = 1\n})\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -47,7 +47,7 @@ type TonnageRunResult = {
|
|
|
47
47
|
};
|
|
48
48
|
//#endregion
|
|
49
49
|
//#region src/define-config.d.ts
|
|
50
|
-
declare function defineConfig(config: TonnageConfig): TonnageConfig;
|
|
50
|
+
export declare function defineConfig(config: TonnageConfig): TonnageConfig;
|
|
51
51
|
//#endregion
|
|
52
52
|
//#region src/measure.d.ts
|
|
53
53
|
type MeasureImportsOptions = {
|
|
@@ -57,25 +57,25 @@ type MeasureImportsOptions = {
|
|
|
57
57
|
target?: string | undefined;
|
|
58
58
|
};
|
|
59
59
|
type MeasureEntryOptions = MeasureImportsOptions;
|
|
60
|
-
declare function measureEntry(entry: string, options: MeasureEntryOptions): Promise<BundleMeasurement>;
|
|
61
|
-
declare function measureImports(imports: readonly string[], options: MeasureImportsOptions): Promise<BundleMeasurement>;
|
|
60
|
+
export declare function measureEntry(entry: string, options: MeasureEntryOptions): Promise<BundleMeasurement>;
|
|
61
|
+
export declare function measureImports(imports: readonly string[], options: MeasureImportsOptions): Promise<BundleMeasurement>;
|
|
62
62
|
//#endregion
|
|
63
63
|
//#region src/readme.d.ts
|
|
64
|
-
declare function tonnageMarkers(marker?: string): {
|
|
64
|
+
export declare function tonnageMarkers(marker?: string): {
|
|
65
65
|
end: string;
|
|
66
66
|
start: string;
|
|
67
67
|
};
|
|
68
|
-
declare function updateGeneratedSection(readme: string, markdown: string, marker?: string): string;
|
|
68
|
+
export declare function updateGeneratedSection(readme: string, markdown: string, marker?: string): string;
|
|
69
69
|
//#endregion
|
|
70
70
|
//#region src/report.d.ts
|
|
71
|
-
declare function createTonnageReport(config: TonnageConfig, configDirectory: string): Promise<TonnageReport>;
|
|
72
|
-
declare function renderTonnageMarkdown(report: TonnageReport, config?: TonnageConfig): string;
|
|
71
|
+
export declare function createTonnageReport(config: TonnageConfig, configDirectory: string): Promise<TonnageReport>;
|
|
72
|
+
export declare function renderTonnageMarkdown(report: TonnageReport, config?: TonnageConfig): string;
|
|
73
73
|
//#endregion
|
|
74
74
|
//#region src/run.d.ts
|
|
75
|
-
declare function runTonnage(config: TonnageConfig, options: {
|
|
75
|
+
export declare function runTonnage(config: TonnageConfig, options: {
|
|
76
76
|
configDirectory?: string;
|
|
77
77
|
mode: TonnageMode;
|
|
78
78
|
}): Promise<TonnageRunResult>;
|
|
79
79
|
//#endregion
|
|
80
|
-
export {
|
|
80
|
+
export type { BundleMeasurement, BundlePlatform, MeasureEntryOptions, MeasureImportsOptions, TonnageConfig, TonnageExports, TonnageMode, TonnageRecipe, TonnageRecipeRow, TonnageReport, TonnageRow, TonnageRunResult };
|
|
81
81
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/define-config.ts","../src/measure.ts","../src/readme.ts","../src/report.ts","../src/run.ts"],"mappings":";;KAAY;KAEA;EACX;EACA;;KAGW;EACX;EACA;EACA;EACA,WAAW;;KAGA;EACX,oBAAoB;EACpB;EACA;EACA;EACA;EACA,WAAW;EACX;EACA,mBAAmB;EACnB;;KAGW;EACX;EACA;;KAGW,aAAa;EACxB;EACA;;KAGW,mBAAmB;EAC9B;EACA;;KAGW;EACX,kBAAkB;EAClB;EACA,kBAAkB;;KAGP;KAEA;EACX;EACA;EACA,QAAQ;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/define-config.ts","../src/measure.ts","../src/readme.ts","../src/report.ts","../src/run.ts"],"mappings":";;KAAY;KAEA;EACX;EACA;;KAGW;EACX;EACA;EACA;EACA,WAAW;;KAGA;EACX,oBAAoB;EACpB;EACA;EACA;EACA;EACA,WAAW;EACX;EACA,mBAAmB;EACnB;;KAGW;EACX;EACA;;KAGW,aAAa;EACxB;EACA;;KAGW,mBAAmB;EAC9B;EACA;;KAGW;EACX,kBAAkB;EAClB;EACA,kBAAkB;;KAGP;KAEA;EACX;EACA;EACA,QAAQ;;;;wBClDO,aAAa,QAAQ,gBAAgB;;;KCKzC;EACX;EACA,WAAW;EACX;EACA;;KAGW,sBAAsB;wBAMZ,aACrB,eACA,SAAS,sBACP,QAAQ;wBAcW,eACrB,4BACA,SAAS,wBACP,QAAQ;;;wBCxCK,eAAe;EAC9B;EACA;;wBASe,uBACf,gBACA,kBACA;;;wBCOqB,oBACrB,QAAQ,eACR,0BACE,QAAQ;wBA+DK,sBACf,QAAQ,eACR,SAAQ;;;wBClFa,WACrB,QAAQ,eACR;EACC;EACA,MAAM;IAEL,QAAQ"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as measureImports, i as measureEntry, n as createTonnageReport, o as tonnageMarkers, r as renderTonnageMarkdown, s as updateGeneratedSection, t as runTonnage } from "./run-
|
|
1
|
+
import { a as measureImports, i as measureEntry, n as createTonnageReport, o as tonnageMarkers, r as renderTonnageMarkdown, s as updateGeneratedSection, t as runTonnage } from "./run-CZ_FO4C7.mjs";
|
|
2
2
|
//#region src/define-config.ts
|
|
3
3
|
function defineConfig(config) {
|
|
4
4
|
return config;
|
|
@@ -188,6 +188,7 @@ function renderTonnageMarkdown(report, config = {}) {
|
|
|
188
188
|
`right`,
|
|
189
189
|
`right`
|
|
190
190
|
]));
|
|
191
|
+
lines.push(``, `Report maintained with [tonnage](https://github.com/jeremybanka/tonnage).`);
|
|
191
192
|
return lines.join(`\n`);
|
|
192
193
|
}
|
|
193
194
|
function methodologyLines({ hasExports, hasRecipes }) {
|
|
@@ -260,4 +261,4 @@ async function runTonnage(config, options) {
|
|
|
260
261
|
//#endregion
|
|
261
262
|
export { measureImports as a, measureEntry as i, createTonnageReport as n, tonnageMarkers as o, renderTonnageMarkdown as r, updateGeneratedSection as s, runTonnage as t };
|
|
262
263
|
|
|
263
|
-
//# sourceMappingURL=run-
|
|
264
|
+
//# sourceMappingURL=run-CZ_FO4C7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-CZ_FO4C7.mjs","names":[],"sources":["../src/readme.ts","../src/measure.ts","../src/package-resolution.ts","../src/report.ts","../src/run.ts"],"sourcesContent":["export function tonnageMarkers(marker = `default`): {\n\tend: string\n\tstart: string\n} {\n\tvalidateMarker(marker)\n\treturn {\n\t\tend: `<!-- tonnage:${marker}:end -->`,\n\t\tstart: `<!-- tonnage:${marker}:start -->`,\n\t}\n}\n\nexport function updateGeneratedSection(\n\treadme: string,\n\tmarkdown: string,\n\tmarker?: string,\n): string {\n\tconst { end, start } = tonnageMarkers(marker)\n\tconst startIndex = readme.indexOf(start)\n\tconst endIndex = readme.indexOf(end)\n\n\tif (startIndex === -1 || endIndex === -1) {\n\t\tthrow new Error(\n\t\t\t`README must contain exactly one ${start} and one ${end} marker.`,\n\t\t)\n\t}\n\tif (\n\t\treadme.slice(startIndex + start.length).includes(start) ||\n\t\treadme.slice(endIndex + end.length).includes(end)\n\t) {\n\t\tthrow new Error(\n\t\t\t`README must contain exactly one ${start} and one ${end} marker.`,\n\t\t)\n\t}\n\tif (endIndex < startIndex) {\n\t\tthrow new Error(`${end} must appear after ${start}.`)\n\t}\n\n\tconst contentStart = startIndex + start.length\n\treturn `${readme.slice(0, contentStart)}\\n\\n${markdown.trim()}\\n\\n${readme.slice(endIndex)}`\n}\n\nfunction validateMarker(marker: string): void {\n\tif (!/^[a-z0-9][a-z0-9._-]*$/i.test(marker)) {\n\t\tthrow new Error(\n\t\t\t`Tonnage marker names may contain letters, numbers, dots, underscores, and hyphens.`,\n\t\t)\n\t}\n}\n","import path from \"node:path\"\nimport { gzipSync } from \"node:zlib\"\n\nimport { build, type BuildOptions, type Plugin } from \"esbuild\"\n\nimport type { BundleMeasurement, BundlePlatform } from \"./types.ts\"\n\nexport type MeasureImportsOptions = {\n\texternal?: readonly string[] | undefined\n\tplatform?: BundlePlatform | undefined\n\tresolveDirectory: string\n\ttarget?: string | undefined\n}\n\nexport type MeasureEntryOptions = MeasureImportsOptions\n\ntype InternalMeasureOptions = MeasureImportsOptions & {\n\tplugins?: readonly Plugin[]\n}\n\nexport async function measureEntry(\n\tentry: string,\n\toptions: MeasureEntryOptions,\n): Promise<BundleMeasurement> {\n\treturn measureEntryWithPlugins(entry, options)\n}\n\nexport async function measureEntryWithPlugins(\n\tentry: string,\n\toptions: InternalMeasureOptions,\n): Promise<BundleMeasurement> {\n\treturn measureBuild(\n\t\t{ entryPoints: [path.resolve(options.resolveDirectory, entry)] },\n\t\toptions,\n\t)\n}\n\nexport async function measureImports(\n\timports: readonly string[],\n\toptions: MeasureImportsOptions,\n): Promise<BundleMeasurement> {\n\treturn measureImportsWithPlugins(imports, options)\n}\n\nexport async function measureImportsWithPlugins(\n\timports: readonly string[],\n\toptions: InternalMeasureOptions,\n): Promise<BundleMeasurement> {\n\tif (imports.length === 0) {\n\t\tthrow new Error(`A tonnage entry must import at least one module.`)\n\t}\n\n\tconst entry = imports\n\t\t.map(\n\t\t\t(specifier, index) =>\n\t\t\t\t`export * as entry${index} from ${JSON.stringify(specifier)}`,\n\t\t)\n\t\t.join(`\\n`)\n\treturn measureBuild(\n\t\t{\n\t\t\tstdin: {\n\t\t\t\tcontents: entry,\n\t\t\t\tloader: `js`,\n\t\t\t\tresolveDir: options.resolveDirectory,\n\t\t\t\tsourcefile: `tonnage-entry.js`,\n\t\t\t},\n\t\t},\n\t\toptions,\n\t)\n}\n\nasync function measureBuild(\n\tentry: Pick<BuildOptions, `entryPoints` | `stdin`>,\n\toptions: InternalMeasureOptions,\n): Promise<BundleMeasurement> {\n\tconst platform = options.platform ?? `neutral`\n\n\tconst result = await build({\n\t\tbundle: true,\n\t\tcharset: `utf8`,\n\t\texternal: [\n\t\t\t...(options.external ?? []),\n\t\t\t...(platform === `browser` ? [] : [`node:*`]),\n\t\t],\n\t\tformat: `esm`,\n\t\tlegalComments: `none`,\n\t\tlogLevel: `silent`,\n\t\t...(platform === `neutral` ? { mainFields: [`module`, `main`] } : {}),\n\t\tminify: true,\n\t\toutdir: `out`,\n\t\tplatform,\n\t\tplugins: [...(options.plugins ?? [])],\n\t\t...entry,\n\t\ttarget: options.target ?? `es2022`,\n\t\ttreeShaking: true,\n\t\twrite: false,\n\t})\n\n\tconst outputFiles = [...(result.outputFiles ?? [])]\n\t\t.filter((output) => output.path.endsWith(`.js`))\n\t\t.sort((left, right) => left.path.localeCompare(right.path))\n\tif (outputFiles.length === 0) {\n\t\tthrow new Error(`The tonnage entry did not emit any runtime JavaScript.`)\n\t}\n\tconst rawBytes = outputFiles.reduce(\n\t\t(total, output) => total + output.contents.byteLength,\n\t\t0,\n\t)\n\tconst gzipBytes = outputFiles.reduce(\n\t\t(total, output) =>\n\t\t\ttotal + gzipSync(output.contents, { level: 9 }).byteLength,\n\t\t0,\n\t)\n\n\treturn { gzipBytes, rawBytes }\n}\n","import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nimport type { Plugin } from \"esbuild\"\n\nexport async function withPackageResolver<Result>(\n\tpackageName: string,\n\tpackageDirectory: string,\n\tuseResolver: (plugin: Plugin) => Promise<Result>,\n): Promise<Result> {\n\tconst temporaryDirectory = await fs.mkdtemp(\n\t\tpath.join(os.tmpdir(), `tonnage-package-`),\n\t)\n\ttry {\n\t\tconst nodeModulesDirectory = path.join(temporaryDirectory, `node_modules`)\n\t\tconst packageLinkPath = path.resolve(nodeModulesDirectory, packageName)\n\t\tif (!packageLinkPath.startsWith(`${nodeModulesDirectory}${path.sep}`)) {\n\t\t\tthrow new Error(`Invalid package name: ${packageName}`)\n\t\t}\n\n\t\tawait fs.mkdir(path.dirname(packageLinkPath), { recursive: true })\n\t\tawait fs.symlink(\n\t\t\tpackageDirectory,\n\t\t\tpackageLinkPath,\n\t\t\tprocess.platform === `win32` ? `junction` : `dir`,\n\t\t)\n\n\t\tconst filter = new RegExp(`^${escapeRegExp(packageName)}(?:/.*)?$`)\n\t\tconst plugin: Plugin = {\n\t\t\tname: `tonnage-package-resolution`,\n\t\t\tsetup(build) {\n\t\t\t\tbuild.onResolve({ filter }, async (args) => {\n\t\t\t\t\tif (args.resolveDir === temporaryDirectory) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\treturn build.resolve(args.path, {\n\t\t\t\t\t\timporter: args.importer,\n\t\t\t\t\t\tkind: args.kind,\n\t\t\t\t\t\tnamespace: args.namespace,\n\t\t\t\t\t\tresolveDir: temporaryDirectory,\n\t\t\t\t\t\twith: args.with,\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t},\n\t\t}\n\n\t\treturn await useResolver(plugin)\n\t} finally {\n\t\tawait fs.rm(temporaryDirectory, { force: true, recursive: true })\n\t}\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, `\\\\$&`)\n}\n","import fs from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport {\n\tmeasureEntryWithPlugins,\n\tmeasureImportsWithPlugins,\n} from \"./measure.ts\"\nimport { withPackageResolver } from \"./package-resolution.ts\"\nimport type {\n\tTonnageConfig,\n\tTonnageExports,\n\tTonnageReport,\n\tTonnageRow,\n} from \"./types.ts\"\n\ntype PackageJson = {\n\texports?: unknown\n\tname?: string\n\tpeerDependencies?: Record<string, string>\n}\n\nexport async function createTonnageReport(\n\tconfig: TonnageConfig,\n\tconfigDirectory: string,\n): Promise<TonnageReport> {\n\tconst packageJsonPath = path.resolve(\n\t\tconfigDirectory,\n\t\tconfig.packageJson ?? `package.json`,\n\t)\n\tconst packageJson = JSON.parse(\n\t\tawait fs.readFile(packageJsonPath, `utf8`),\n\t) as PackageJson\n\tif (!packageJson.name) {\n\t\tthrow new Error(`${packageJsonPath} does not declare a package name.`)\n\t}\n\n\tconst resolveDirectory = path.dirname(packageJsonPath)\n\tconst peerDependencies = Object.keys(packageJson.peerDependencies ?? {})\n\tconst external = unique([...peerDependencies, ...(config.external ?? [])])\n\tconst exportImports = selectExportImports(\n\t\tpackageJson.name,\n\t\tpackageJson.exports,\n\t\tconfig.exports,\n\t)\n\n\tconst { exportRows, recipeRows } = await withPackageResolver(\n\t\tpackageJson.name,\n\t\tresolveDirectory,\n\t\tasync (packageResolver) => {\n\t\t\tconst exportRows = await Promise.all(\n\t\t\t\texportImports.map(async (specifier): Promise<TonnageRow> => ({\n\t\t\t\t\t...(await measureImportsWithPlugins([specifier], {\n\t\t\t\t\t\texternal,\n\t\t\t\t\t\tplatform: config.platform,\n\t\t\t\t\t\tplugins: [packageResolver],\n\t\t\t\t\t\tresolveDirectory,\n\t\t\t\t\t\ttarget: config.target,\n\t\t\t\t\t})),\n\t\t\t\t\timports: [specifier],\n\t\t\t\t\tname: specifier,\n\t\t\t\t})),\n\t\t\t)\n\t\t\tconst recipeRows = await Promise.all(\n\t\t\t\t(config.recipes ?? []).map(async (recipe) => ({\n\t\t\t\t\t...(await measureEntryWithPlugins(recipe.entry, {\n\t\t\t\t\t\texternal: unique([...external, ...(recipe.external ?? [])]),\n\t\t\t\t\t\tplatform: recipe.platform ?? config.platform,\n\t\t\t\t\t\tplugins: [packageResolver],\n\t\t\t\t\t\tresolveDirectory,\n\t\t\t\t\t\ttarget: config.target,\n\t\t\t\t\t})),\n\t\t\t\t\tentry: recipe.entry,\n\t\t\t\t\tname: recipe.name,\n\t\t\t\t})),\n\t\t\t)\n\n\t\t\treturn { exportRows, recipeRows }\n\t\t},\n\t)\n\n\treturn {\n\t\texports: exportRows,\n\t\tpackageName: packageJson.name,\n\t\trecipes: recipeRows,\n\t}\n}\n\nexport function renderTonnageMarkdown(\n\treport: TonnageReport,\n\tconfig: TonnageConfig = {},\n): string {\n\tconst hasExports = report.exports.length > 0\n\tconst hasRecipes = report.recipes.length > 0\n\tconst hasMultipleSections = hasExports && hasRecipes\n\tconst lines = [\n\t\t`## ${config.heading ?? `Bundle size`}`,\n\t\t``,\n\t\t...methodologyLines({ hasExports, hasRecipes }),\n\t]\n\n\tif (hasExports) {\n\t\tlines.push(\n\t\t\t``,\n\t\t\t...(hasMultipleSections ? [`### Package exports`, ``] : []),\n\t\t\t...markdownTable(\n\t\t\t\t[`Import`, `Minified JS`, `Gzip JS`],\n\t\t\t\treport.exports.map((row) => [\n\t\t\t\t\tcode(row.name),\n\t\t\t\t\tformatBytes(row.rawBytes),\n\t\t\t\t\tformatBytes(row.gzipBytes),\n\t\t\t\t]),\n\t\t\t\t[`left`, `right`, `right`],\n\t\t\t),\n\t\t)\n\t}\n\n\tif (hasRecipes) {\n\t\tlines.push(\n\t\t\t``,\n\t\t\t...(hasMultipleSections ? [`### Usage examples`, ``] : []),\n\t\t\t...markdownTable(\n\t\t\t\t[`Recipe`, `Entry`, `Minified JS`, `Gzip JS`],\n\t\t\t\treport.recipes.map((row) => [\n\t\t\t\t\tescapeCell(row.name),\n\t\t\t\t\tcode(row.entry),\n\t\t\t\t\tformatBytes(row.rawBytes),\n\t\t\t\t\tformatBytes(row.gzipBytes),\n\t\t\t\t]),\n\t\t\t\t[`left`, `left`, `right`, `right`],\n\t\t\t),\n\t\t)\n\t}\n\n\tlines.push(\n\t\t``,\n\t\t`Report maintained with [tonnage](https://github.com/jeremybanka/tonnage).`,\n\t)\n\n\treturn lines.join(`\\n`)\n}\n\nfunction methodologyLines({\n\thasExports,\n\thasRecipes,\n}: {\n\thasExports: boolean\n\thasRecipes: boolean\n}): string[] {\n\tconst lines: string[] = []\n\tif (hasExports) {\n\t\tlines.push(`Package export sizes include complete runtime export surfaces.`)\n\t}\n\tif (hasRecipes) {\n\t\tlines.push(\n\t\t\t`Usage example sizes bundle their entry files and tree-shake unused exports.`,\n\t\t)\n\t}\n\tlines.push(\n\t\t`Sizes are exact minified and level-9 gzip JavaScript byte counts. Declarations, source maps, CSS, and other assets are excluded. Peer dependencies stay external, and shared modules are counted once per bundle.`,\n\t)\n\treturn lines\n}\n\nfunction selectExportImports(\n\tpackageName: string,\n\texportsValue: unknown,\n\tselection: TonnageConfig[`exports`],\n): string[] {\n\tif (selection === false) {\n\t\treturn []\n\t}\n\n\tconst exportKeys = getExportKeys(exportsValue)\n\tconst options: TonnageExports = typeof selection === `object` ? selection : {}\n\tconst included = options.include\n\t\t? [...options.include]\n\t\t: exportKeys.filter((exportKey) => exportKey !== `./package.json`)\n\tconst excluded = new Set(options.exclude ?? [])\n\n\treturn included\n\t\t.filter((exportKey) => !excluded.has(exportKey))\n\t\t.map((exportKey) => toPackageImport(packageName, exportKey))\n}\n\nfunction getExportKeys(exportsValue: unknown): string[] {\n\tif (typeof exportsValue === `string` || Array.isArray(exportsValue)) {\n\t\treturn [`.`]\n\t}\n\tif (!exportsValue || typeof exportsValue !== `object`) {\n\t\treturn [`.`]\n\t}\n\n\tconst keys = Object.keys(exportsValue)\n\treturn keys.some((key) => key.startsWith(`.`)) ? keys : [`.`]\n}\n\nfunction toPackageImport(packageName: string, exportKey: string): string {\n\tif (exportKey === `.`) {\n\t\treturn packageName\n\t}\n\tif (!exportKey.startsWith(`./`)) {\n\t\tthrow new Error(`Invalid package export key: ${exportKey}`)\n\t}\n\treturn `${packageName}/${exportKey.slice(2)}`\n}\n\nfunction formatBytes(bytes: number): string {\n\treturn `${new Intl.NumberFormat(`en-US`).format(bytes)} B`\n}\n\nfunction code(value: string): string {\n\treturn `<code>${escapeCell(value)}</code>`\n}\n\nfunction escapeCell(value: string): string {\n\treturn value.replaceAll(`&`, `&`).replaceAll(`|`, `|`)\n}\n\nfunction unique(values: readonly string[]): string[] {\n\treturn [...new Set(values)]\n}\n\nfunction markdownTable(\n\theadings: readonly string[],\n\trows: readonly (readonly string[])[],\n\talignments: readonly (`left` | `right`)[],\n): string[] {\n\tconst widths = headings.map((heading, column) =>\n\t\tMath.max(heading.length, ...rows.map((row) => row[column]?.length ?? 0), 3),\n\t)\n\tconst renderRow = (cells: readonly string[]): string =>\n\t\t`| ${cells.map((cell, column) => padCell(cell, widths[column] ?? 3, alignments[column] ?? `left`)).join(` | `)} |`\n\tconst separator = widths.map((width, column) =>\n\t\talignments[column] === `right`\n\t\t\t? `${`-`.repeat(width - 1)}:`\n\t\t\t: `-`.repeat(width),\n\t)\n\n\treturn [renderRow(headings), renderRow(separator), ...rows.map(renderRow)]\n}\n\nfunction padCell(\n\tcell: string,\n\twidth: number,\n\talignment: `left` | `right`,\n): string {\n\treturn alignment === `right` ? cell.padStart(width) : cell.padEnd(width)\n}\n","import fs from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport { updateGeneratedSection } from \"./readme.ts\"\nimport { createTonnageReport, renderTonnageMarkdown } from \"./report.ts\"\nimport type { TonnageConfig, TonnageMode, TonnageRunResult } from \"./types.ts\"\n\nexport async function runTonnage(\n\tconfig: TonnageConfig,\n\toptions: {\n\t\tconfigDirectory?: string\n\t\tmode: TonnageMode\n\t},\n): Promise<TonnageRunResult> {\n\tconst configDirectory = path.resolve(options.configDirectory ?? process.cwd())\n\tconst readmePath = path.resolve(configDirectory, config.readme ?? `README.md`)\n\tconst oldReadme = await fs.readFile(readmePath, `utf8`)\n\tconst report = await createTonnageReport(config, configDirectory)\n\tconst markdown = renderTonnageMarkdown(report, config)\n\tconst newReadme = updateGeneratedSection(oldReadme, markdown, config.marker)\n\tconst changed = oldReadme !== newReadme\n\n\tif (options.mode === `write` && changed) {\n\t\tawait fs.writeFile(readmePath, newReadme)\n\t}\n\n\treturn { changed, readmePath, report }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tonnage",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Keep deterministic bundle size reports in README files and CI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -37,11 +37,11 @@
|
|
|
37
37
|
"main": "./dist/index.mjs",
|
|
38
38
|
"types": "./dist/index.d.mts",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"comline": "0.
|
|
40
|
+
"comline": "0.7.0",
|
|
41
41
|
"esbuild": "0.28.2"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@types/node": "26.
|
|
44
|
+
"@types/node": "26.5.1",
|
|
45
45
|
"vitest": "npm:@voidzero-dev/vite-plus-test@0.1.24"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
package/src/cli.ts
CHANGED
|
@@ -4,7 +4,13 @@ import fs from "node:fs/promises"
|
|
|
4
4
|
import path from "node:path"
|
|
5
5
|
import { pathToFileURL } from "node:url"
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { logWarnings } from "comline"
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
completeTonnageCli,
|
|
11
|
+
parseTonnageCli,
|
|
12
|
+
renderTonnageCliHelp,
|
|
13
|
+
} from "./command-line.ts"
|
|
8
14
|
import { runTonnage } from "./run.ts"
|
|
9
15
|
import type { TonnageConfig } from "./types.ts"
|
|
10
16
|
|
|
@@ -15,7 +21,14 @@ const DEFAULT_CONFIG_FILES = [
|
|
|
15
21
|
]
|
|
16
22
|
|
|
17
23
|
async function main(): Promise<void> {
|
|
18
|
-
const
|
|
24
|
+
const completion = await completeTonnageCli(process.argv)
|
|
25
|
+
if (completion !== undefined) {
|
|
26
|
+
process.stdout.write(completion)
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const invocation = parseTonnageCli(process.argv)
|
|
31
|
+
logWarnings(invocation.warnings)
|
|
19
32
|
if (invocation.kind === `help`) {
|
|
20
33
|
process.stdout.write(renderTonnageCliHelp())
|
|
21
34
|
return
|
package/src/command-line.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type CliWarning,
|
|
3
|
+
cli,
|
|
4
|
+
completionResponse,
|
|
5
|
+
help,
|
|
6
|
+
helpOption,
|
|
7
|
+
optional,
|
|
8
|
+
} from "comline"
|
|
2
9
|
|
|
3
10
|
import type { TonnageMode } from "./types.ts"
|
|
4
11
|
|
|
@@ -22,18 +29,29 @@ const tonnageCli = cli({
|
|
|
22
29
|
write: WRITE_MANUAL,
|
|
23
30
|
"write/$configPath": WRITE_MANUAL,
|
|
24
31
|
},
|
|
32
|
+
positionalCompletions: {
|
|
33
|
+
"check/$configPath": { fileSystem: `files` },
|
|
34
|
+
"write/$configPath": { fileSystem: `files` },
|
|
35
|
+
},
|
|
25
36
|
discoverConfigPath: () => undefined,
|
|
26
37
|
})
|
|
27
38
|
|
|
28
|
-
export type TonnageCliInvocation =
|
|
39
|
+
export type TonnageCliInvocation = { warnings: CliWarning[] } & (
|
|
29
40
|
| { kind: `help` }
|
|
30
41
|
| { configArgument?: string; kind: `run`; mode: TonnageMode }
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
export function completeTonnageCli(
|
|
45
|
+
args: string[],
|
|
46
|
+
): Promise<string | undefined> {
|
|
47
|
+
return completionResponse(tonnageCli.definition, args)
|
|
48
|
+
}
|
|
31
49
|
|
|
32
50
|
export function parseTonnageCli(args: string[]): TonnageCliInvocation {
|
|
33
|
-
const { inputs } = tonnageCli(args)
|
|
51
|
+
const { inputs, warnings } = tonnageCli(args)
|
|
34
52
|
|
|
35
53
|
if (inputs.case === `` || inputs.opts.help) {
|
|
36
|
-
return { kind: `help
|
|
54
|
+
return { kind: `help`, warnings }
|
|
37
55
|
}
|
|
38
56
|
|
|
39
57
|
const mode =
|
|
@@ -43,8 +61,8 @@ export function parseTonnageCli(args: string[]): TonnageCliInvocation {
|
|
|
43
61
|
const configArgument = inputs.path[1]
|
|
44
62
|
|
|
45
63
|
return configArgument === undefined
|
|
46
|
-
? { kind: `run`, mode }
|
|
47
|
-
: { configArgument, kind: `run`, mode }
|
|
64
|
+
? { kind: `run`, mode, warnings }
|
|
65
|
+
: { configArgument, kind: `run`, mode, warnings }
|
|
48
66
|
}
|
|
49
67
|
|
|
50
68
|
export function renderTonnageCliHelp(): string {
|
package/src/report.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"run-P2rhqYM3.mjs","names":[],"sources":["../src/readme.ts","../src/measure.ts","../src/package-resolution.ts","../src/report.ts","../src/run.ts"],"sourcesContent":["export function tonnageMarkers(marker = `default`): {\n\tend: string\n\tstart: string\n} {\n\tvalidateMarker(marker)\n\treturn {\n\t\tend: `<!-- tonnage:${marker}:end -->`,\n\t\tstart: `<!-- tonnage:${marker}:start -->`,\n\t}\n}\n\nexport function updateGeneratedSection(\n\treadme: string,\n\tmarkdown: string,\n\tmarker?: string,\n): string {\n\tconst { end, start } = tonnageMarkers(marker)\n\tconst startIndex = readme.indexOf(start)\n\tconst endIndex = readme.indexOf(end)\n\n\tif (startIndex === -1 || endIndex === -1) {\n\t\tthrow new Error(\n\t\t\t`README must contain exactly one ${start} and one ${end} marker.`,\n\t\t)\n\t}\n\tif (\n\t\treadme.slice(startIndex + start.length).includes(start) ||\n\t\treadme.slice(endIndex + end.length).includes(end)\n\t) {\n\t\tthrow new Error(\n\t\t\t`README must contain exactly one ${start} and one ${end} marker.`,\n\t\t)\n\t}\n\tif (endIndex < startIndex) {\n\t\tthrow new Error(`${end} must appear after ${start}.`)\n\t}\n\n\tconst contentStart = startIndex + start.length\n\treturn `${readme.slice(0, contentStart)}\\n\\n${markdown.trim()}\\n\\n${readme.slice(endIndex)}`\n}\n\nfunction validateMarker(marker: string): void {\n\tif (!/^[a-z0-9][a-z0-9._-]*$/i.test(marker)) {\n\t\tthrow new Error(\n\t\t\t`Tonnage marker names may contain letters, numbers, dots, underscores, and hyphens.`,\n\t\t)\n\t}\n}\n","import path from \"node:path\"\nimport { gzipSync } from \"node:zlib\"\n\nimport { build, type BuildOptions, type Plugin } from \"esbuild\"\n\nimport type { BundleMeasurement, BundlePlatform } from \"./types.ts\"\n\nexport type MeasureImportsOptions = {\n\texternal?: readonly string[] | undefined\n\tplatform?: BundlePlatform | undefined\n\tresolveDirectory: string\n\ttarget?: string | undefined\n}\n\nexport type MeasureEntryOptions = MeasureImportsOptions\n\ntype InternalMeasureOptions = MeasureImportsOptions & {\n\tplugins?: readonly Plugin[]\n}\n\nexport async function measureEntry(\n\tentry: string,\n\toptions: MeasureEntryOptions,\n): Promise<BundleMeasurement> {\n\treturn measureEntryWithPlugins(entry, options)\n}\n\nexport async function measureEntryWithPlugins(\n\tentry: string,\n\toptions: InternalMeasureOptions,\n): Promise<BundleMeasurement> {\n\treturn measureBuild(\n\t\t{ entryPoints: [path.resolve(options.resolveDirectory, entry)] },\n\t\toptions,\n\t)\n}\n\nexport async function measureImports(\n\timports: readonly string[],\n\toptions: MeasureImportsOptions,\n): Promise<BundleMeasurement> {\n\treturn measureImportsWithPlugins(imports, options)\n}\n\nexport async function measureImportsWithPlugins(\n\timports: readonly string[],\n\toptions: InternalMeasureOptions,\n): Promise<BundleMeasurement> {\n\tif (imports.length === 0) {\n\t\tthrow new Error(`A tonnage entry must import at least one module.`)\n\t}\n\n\tconst entry = imports\n\t\t.map(\n\t\t\t(specifier, index) =>\n\t\t\t\t`export * as entry${index} from ${JSON.stringify(specifier)}`,\n\t\t)\n\t\t.join(`\\n`)\n\treturn measureBuild(\n\t\t{\n\t\t\tstdin: {\n\t\t\t\tcontents: entry,\n\t\t\t\tloader: `js`,\n\t\t\t\tresolveDir: options.resolveDirectory,\n\t\t\t\tsourcefile: `tonnage-entry.js`,\n\t\t\t},\n\t\t},\n\t\toptions,\n\t)\n}\n\nasync function measureBuild(\n\tentry: Pick<BuildOptions, `entryPoints` | `stdin`>,\n\toptions: InternalMeasureOptions,\n): Promise<BundleMeasurement> {\n\tconst platform = options.platform ?? `neutral`\n\n\tconst result = await build({\n\t\tbundle: true,\n\t\tcharset: `utf8`,\n\t\texternal: [\n\t\t\t...(options.external ?? []),\n\t\t\t...(platform === `browser` ? [] : [`node:*`]),\n\t\t],\n\t\tformat: `esm`,\n\t\tlegalComments: `none`,\n\t\tlogLevel: `silent`,\n\t\t...(platform === `neutral` ? { mainFields: [`module`, `main`] } : {}),\n\t\tminify: true,\n\t\toutdir: `out`,\n\t\tplatform,\n\t\tplugins: [...(options.plugins ?? [])],\n\t\t...entry,\n\t\ttarget: options.target ?? `es2022`,\n\t\ttreeShaking: true,\n\t\twrite: false,\n\t})\n\n\tconst outputFiles = [...(result.outputFiles ?? [])]\n\t\t.filter((output) => output.path.endsWith(`.js`))\n\t\t.sort((left, right) => left.path.localeCompare(right.path))\n\tif (outputFiles.length === 0) {\n\t\tthrow new Error(`The tonnage entry did not emit any runtime JavaScript.`)\n\t}\n\tconst rawBytes = outputFiles.reduce(\n\t\t(total, output) => total + output.contents.byteLength,\n\t\t0,\n\t)\n\tconst gzipBytes = outputFiles.reduce(\n\t\t(total, output) =>\n\t\t\ttotal + gzipSync(output.contents, { level: 9 }).byteLength,\n\t\t0,\n\t)\n\n\treturn { gzipBytes, rawBytes }\n}\n","import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nimport type { Plugin } from \"esbuild\"\n\nexport async function withPackageResolver<Result>(\n\tpackageName: string,\n\tpackageDirectory: string,\n\tuseResolver: (plugin: Plugin) => Promise<Result>,\n): Promise<Result> {\n\tconst temporaryDirectory = await fs.mkdtemp(\n\t\tpath.join(os.tmpdir(), `tonnage-package-`),\n\t)\n\ttry {\n\t\tconst nodeModulesDirectory = path.join(temporaryDirectory, `node_modules`)\n\t\tconst packageLinkPath = path.resolve(nodeModulesDirectory, packageName)\n\t\tif (!packageLinkPath.startsWith(`${nodeModulesDirectory}${path.sep}`)) {\n\t\t\tthrow new Error(`Invalid package name: ${packageName}`)\n\t\t}\n\n\t\tawait fs.mkdir(path.dirname(packageLinkPath), { recursive: true })\n\t\tawait fs.symlink(\n\t\t\tpackageDirectory,\n\t\t\tpackageLinkPath,\n\t\t\tprocess.platform === `win32` ? `junction` : `dir`,\n\t\t)\n\n\t\tconst filter = new RegExp(`^${escapeRegExp(packageName)}(?:/.*)?$`)\n\t\tconst plugin: Plugin = {\n\t\t\tname: `tonnage-package-resolution`,\n\t\t\tsetup(build) {\n\t\t\t\tbuild.onResolve({ filter }, async (args) => {\n\t\t\t\t\tif (args.resolveDir === temporaryDirectory) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\treturn build.resolve(args.path, {\n\t\t\t\t\t\timporter: args.importer,\n\t\t\t\t\t\tkind: args.kind,\n\t\t\t\t\t\tnamespace: args.namespace,\n\t\t\t\t\t\tresolveDir: temporaryDirectory,\n\t\t\t\t\t\twith: args.with,\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t},\n\t\t}\n\n\t\treturn await useResolver(plugin)\n\t} finally {\n\t\tawait fs.rm(temporaryDirectory, { force: true, recursive: true })\n\t}\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, `\\\\$&`)\n}\n","import fs from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport {\n\tmeasureEntryWithPlugins,\n\tmeasureImportsWithPlugins,\n} from \"./measure.ts\"\nimport { withPackageResolver } from \"./package-resolution.ts\"\nimport type {\n\tTonnageConfig,\n\tTonnageExports,\n\tTonnageReport,\n\tTonnageRow,\n} from \"./types.ts\"\n\ntype PackageJson = {\n\texports?: unknown\n\tname?: string\n\tpeerDependencies?: Record<string, string>\n}\n\nexport async function createTonnageReport(\n\tconfig: TonnageConfig,\n\tconfigDirectory: string,\n): Promise<TonnageReport> {\n\tconst packageJsonPath = path.resolve(\n\t\tconfigDirectory,\n\t\tconfig.packageJson ?? `package.json`,\n\t)\n\tconst packageJson = JSON.parse(\n\t\tawait fs.readFile(packageJsonPath, `utf8`),\n\t) as PackageJson\n\tif (!packageJson.name) {\n\t\tthrow new Error(`${packageJsonPath} does not declare a package name.`)\n\t}\n\n\tconst resolveDirectory = path.dirname(packageJsonPath)\n\tconst peerDependencies = Object.keys(packageJson.peerDependencies ?? {})\n\tconst external = unique([...peerDependencies, ...(config.external ?? [])])\n\tconst exportImports = selectExportImports(\n\t\tpackageJson.name,\n\t\tpackageJson.exports,\n\t\tconfig.exports,\n\t)\n\n\tconst { exportRows, recipeRows } = await withPackageResolver(\n\t\tpackageJson.name,\n\t\tresolveDirectory,\n\t\tasync (packageResolver) => {\n\t\t\tconst exportRows = await Promise.all(\n\t\t\t\texportImports.map(async (specifier): Promise<TonnageRow> => ({\n\t\t\t\t\t...(await measureImportsWithPlugins([specifier], {\n\t\t\t\t\t\texternal,\n\t\t\t\t\t\tplatform: config.platform,\n\t\t\t\t\t\tplugins: [packageResolver],\n\t\t\t\t\t\tresolveDirectory,\n\t\t\t\t\t\ttarget: config.target,\n\t\t\t\t\t})),\n\t\t\t\t\timports: [specifier],\n\t\t\t\t\tname: specifier,\n\t\t\t\t})),\n\t\t\t)\n\t\t\tconst recipeRows = await Promise.all(\n\t\t\t\t(config.recipes ?? []).map(async (recipe) => ({\n\t\t\t\t\t...(await measureEntryWithPlugins(recipe.entry, {\n\t\t\t\t\t\texternal: unique([...external, ...(recipe.external ?? [])]),\n\t\t\t\t\t\tplatform: recipe.platform ?? config.platform,\n\t\t\t\t\t\tplugins: [packageResolver],\n\t\t\t\t\t\tresolveDirectory,\n\t\t\t\t\t\ttarget: config.target,\n\t\t\t\t\t})),\n\t\t\t\t\tentry: recipe.entry,\n\t\t\t\t\tname: recipe.name,\n\t\t\t\t})),\n\t\t\t)\n\n\t\t\treturn { exportRows, recipeRows }\n\t\t},\n\t)\n\n\treturn {\n\t\texports: exportRows,\n\t\tpackageName: packageJson.name,\n\t\trecipes: recipeRows,\n\t}\n}\n\nexport function renderTonnageMarkdown(\n\treport: TonnageReport,\n\tconfig: TonnageConfig = {},\n): string {\n\tconst hasExports = report.exports.length > 0\n\tconst hasRecipes = report.recipes.length > 0\n\tconst hasMultipleSections = hasExports && hasRecipes\n\tconst lines = [\n\t\t`## ${config.heading ?? `Bundle size`}`,\n\t\t``,\n\t\t...methodologyLines({ hasExports, hasRecipes }),\n\t]\n\n\tif (hasExports) {\n\t\tlines.push(\n\t\t\t``,\n\t\t\t...(hasMultipleSections ? [`### Package exports`, ``] : []),\n\t\t\t...markdownTable(\n\t\t\t\t[`Import`, `Minified JS`, `Gzip JS`],\n\t\t\t\treport.exports.map((row) => [\n\t\t\t\t\tcode(row.name),\n\t\t\t\t\tformatBytes(row.rawBytes),\n\t\t\t\t\tformatBytes(row.gzipBytes),\n\t\t\t\t]),\n\t\t\t\t[`left`, `right`, `right`],\n\t\t\t),\n\t\t)\n\t}\n\n\tif (hasRecipes) {\n\t\tlines.push(\n\t\t\t``,\n\t\t\t...(hasMultipleSections ? [`### Usage examples`, ``] : []),\n\t\t\t...markdownTable(\n\t\t\t\t[`Recipe`, `Entry`, `Minified JS`, `Gzip JS`],\n\t\t\t\treport.recipes.map((row) => [\n\t\t\t\t\tescapeCell(row.name),\n\t\t\t\t\tcode(row.entry),\n\t\t\t\t\tformatBytes(row.rawBytes),\n\t\t\t\t\tformatBytes(row.gzipBytes),\n\t\t\t\t]),\n\t\t\t\t[`left`, `left`, `right`, `right`],\n\t\t\t),\n\t\t)\n\t}\n\n\treturn lines.join(`\\n`)\n}\n\nfunction methodologyLines({\n\thasExports,\n\thasRecipes,\n}: {\n\thasExports: boolean\n\thasRecipes: boolean\n}): string[] {\n\tconst lines: string[] = []\n\tif (hasExports) {\n\t\tlines.push(`Package export sizes include complete runtime export surfaces.`)\n\t}\n\tif (hasRecipes) {\n\t\tlines.push(\n\t\t\t`Usage example sizes bundle their entry files and tree-shake unused exports.`,\n\t\t)\n\t}\n\tlines.push(\n\t\t`Sizes are exact minified and level-9 gzip JavaScript byte counts. Declarations, source maps, CSS, and other assets are excluded. Peer dependencies stay external, and shared modules are counted once per bundle.`,\n\t)\n\treturn lines\n}\n\nfunction selectExportImports(\n\tpackageName: string,\n\texportsValue: unknown,\n\tselection: TonnageConfig[`exports`],\n): string[] {\n\tif (selection === false) {\n\t\treturn []\n\t}\n\n\tconst exportKeys = getExportKeys(exportsValue)\n\tconst options: TonnageExports = typeof selection === `object` ? selection : {}\n\tconst included = options.include\n\t\t? [...options.include]\n\t\t: exportKeys.filter((exportKey) => exportKey !== `./package.json`)\n\tconst excluded = new Set(options.exclude ?? [])\n\n\treturn included\n\t\t.filter((exportKey) => !excluded.has(exportKey))\n\t\t.map((exportKey) => toPackageImport(packageName, exportKey))\n}\n\nfunction getExportKeys(exportsValue: unknown): string[] {\n\tif (typeof exportsValue === `string` || Array.isArray(exportsValue)) {\n\t\treturn [`.`]\n\t}\n\tif (!exportsValue || typeof exportsValue !== `object`) {\n\t\treturn [`.`]\n\t}\n\n\tconst keys = Object.keys(exportsValue)\n\treturn keys.some((key) => key.startsWith(`.`)) ? keys : [`.`]\n}\n\nfunction toPackageImport(packageName: string, exportKey: string): string {\n\tif (exportKey === `.`) {\n\t\treturn packageName\n\t}\n\tif (!exportKey.startsWith(`./`)) {\n\t\tthrow new Error(`Invalid package export key: ${exportKey}`)\n\t}\n\treturn `${packageName}/${exportKey.slice(2)}`\n}\n\nfunction formatBytes(bytes: number): string {\n\treturn `${new Intl.NumberFormat(`en-US`).format(bytes)} B`\n}\n\nfunction code(value: string): string {\n\treturn `<code>${escapeCell(value)}</code>`\n}\n\nfunction escapeCell(value: string): string {\n\treturn value.replaceAll(`&`, `&`).replaceAll(`|`, `|`)\n}\n\nfunction unique(values: readonly string[]): string[] {\n\treturn [...new Set(values)]\n}\n\nfunction markdownTable(\n\theadings: readonly string[],\n\trows: readonly (readonly string[])[],\n\talignments: readonly (`left` | `right`)[],\n): string[] {\n\tconst widths = headings.map((heading, column) =>\n\t\tMath.max(heading.length, ...rows.map((row) => row[column]?.length ?? 0), 3),\n\t)\n\tconst renderRow = (cells: readonly string[]): string =>\n\t\t`| ${cells.map((cell, column) => padCell(cell, widths[column] ?? 3, alignments[column] ?? `left`)).join(` | `)} |`\n\tconst separator = widths.map((width, column) =>\n\t\talignments[column] === `right`\n\t\t\t? `${`-`.repeat(width - 1)}:`\n\t\t\t: `-`.repeat(width),\n\t)\n\n\treturn [renderRow(headings), renderRow(separator), ...rows.map(renderRow)]\n}\n\nfunction padCell(\n\tcell: string,\n\twidth: number,\n\talignment: `left` | `right`,\n): string {\n\treturn alignment === `right` ? cell.padStart(width) : cell.padEnd(width)\n}\n","import fs from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport { updateGeneratedSection } from \"./readme.ts\"\nimport { createTonnageReport, renderTonnageMarkdown } from \"./report.ts\"\nimport type { TonnageConfig, TonnageMode, TonnageRunResult } from \"./types.ts\"\n\nexport async function runTonnage(\n\tconfig: TonnageConfig,\n\toptions: {\n\t\tconfigDirectory?: string\n\t\tmode: TonnageMode\n\t},\n): Promise<TonnageRunResult> {\n\tconst configDirectory = path.resolve(options.configDirectory ?? process.cwd())\n\tconst readmePath = path.resolve(configDirectory, config.readme ?? `README.md`)\n\tconst oldReadme = await fs.readFile(readmePath, `utf8`)\n\tconst report = await createTonnageReport(config, configDirectory)\n\tconst markdown = renderTonnageMarkdown(report, config)\n\tconst newReadme = updateGeneratedSection(oldReadme, markdown, config.marker)\n\tconst changed = oldReadme !== newReadme\n\n\tif (options.mode === `write` && changed) {\n\t\tawait fs.writeFile(readmePath, newReadme)\n\t}\n\n\treturn { changed, readmePath, report }\n}\n"],"mappings":"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"}
|