import { encode } from "@jridgewell/sourcemap-codec"; import { expect } from "@std/expect"; import { describe, it as test } from "@std/testing/bdd"; import { applicationArea, attributeGeneratedBytes, type BundleSourceMap, categoryForSource, dependencyName, groupSourceBytes, sourceLineKey, } from "#scripts/bench/bundle-composition/model.ts"; const sourceMap = ( sources: string[], lines: Parameters[0], ): BundleSourceMap => ({ mappings: encode(lines), sources }); describe("bundle composition model", () => { test("attributes generated bytes and unmapped text", () => { const result = attributeGeneratedBytes( "abcde\nx", sourceMap( ["a.ts", "b.ts"], [ [ [0, 0, 0, 0], [4, 1, 2, 0], ], ], ), ); expect(result.totalBytes).toBe(7); expect(result.bySource).toEqual([ { bytes: 4, source: "a.ts" }, { bytes: 2, source: "[unmapped]" }, { bytes: 1, source: "b.ts" }, ]); expect(result.bySourceLine.get(sourceLineKey("b.ts", 2))).toBe(1); }); test("counts UTF-8 bytes from UTF-16 source-map columns", () => { const result = attributeGeneratedBytes( "éx", sourceMap( ["accent.ts", "plain.ts"], [ [ [0, 0, 0, 0], [1, 1, 0, 0], ], ], ), ); expect(result.bySource).toEqual([ { bytes: 2, source: "accent.ts" }, { bytes: 1, source: "plain.ts" }, ]); }); test("attributes prefixes and unmapped segments", () => { const prefixed = attributeGeneratedBytes( "--abc", sourceMap(["mapped.ts"], [[[2, 0, 0, 0]]]), ); const unmapped = attributeGeneratedBytes("raw", sourceMap([], [[[0]]])); expect(prefixed.bySource).toEqual([ { bytes: 3, source: "mapped.ts" }, { bytes: 2, source: "[unmapped]" }, ]); expect(unmapped.bySource).toEqual([{ bytes: 3, source: "[unmapped]" }]); }); test("rejects a mapping whose source is missing", () => { expect(() => attributeGeneratedBytes("x", sourceMap([], [[[0, 2, 0, 0]]])), ).toThrow("Missing source-map source 2"); }); test("classifies production source families", () => { expect(categoryForSource("inline-jsquash-wasm:bytes.ts")).toBe( "Inlined WASM", ); expect(categoryForSource("inline-assets:#routes/assets.ts")).toBe( "Inlined browser/static module", ); expect(categoryForSource("../src/shared/db/client.ts")).toBe( "Application source", ); expect(categoryForSource("https://jsr.io/@std/path/1.0.0/mod.ts")).toBe( "JSR dependencies", ); expect(categoryForSource("cache/node_modules/stripe/index.js")).toBe( "npm dependencies", ); expect(categoryForSource("[unmapped]")).toBe( "Build glue and generated code", ); }); test("extracts npm and JSR package names", () => { expect(dependencyName("cache/node_modules/@sentry/core/index.js")).toBe( "@sentry/core", ); expect(dependencyName("https://jsr.io/@std/media-types/1.1.0/mod.ts")).toBe( "@std/media-types", ); expect(dependencyName("cache/node_modules/stripe/index.js")).toBe("stripe"); expect(dependencyName("https://jsr.io/@std")).toBeNull(); expect(dependencyName("../src/shared/sentry.ts")).toBeNull(); }); test("groups every application family by its narrowest area", () => { const examples = [ ["../src/shared/db/migrations.ts", "Database migrations"], ["../src/shared/db/migrations/one.ts", "Database migrations"], ["../src/locales/en/admin.json", "Locales"], ["../src/ui/templates/admin/page.tsx", "Admin templates"], ["../src/features/admin/page.ts", "Admin routes"], ["../src/ui/templates/public/page.tsx", "Public templates"], ["../src/features/public/order.ts", "Public routes"], ["../src/features/api/webhook.ts", "API routes and webhooks"], ["../src/shared/db/client.ts", "Shared database code"], ["../src/ui/templates/layout.tsx", "Shared UI templates"], ["../src/shared/currency.ts", "Shared domain and runtime"], ["../src/features/index.ts", "Other features and routing"], ["../src/edge.ts", "Entry and root modules"], ] as const; expect(examples.map(([source]) => applicationArea(source))).toEqual( examples.map(([, area]) => area), ); expect(applicationArea("cache/node_modules/pkg/index.js")).toBeNull(); }); test("adds bytes sharing the same report name", () => { expect( groupSourceBytes( [ { bytes: 3, source: "b-one" }, { bytes: 4, source: "a-one" }, { bytes: 6, source: "a-two" }, { bytes: 3, source: "skip" }, ], (source) => (source === "skip" ? null : source.slice(0, 1)), ), ).toEqual([ { bytes: 10, source: "a" }, { bytes: 3, source: "b" }, ]); }); });