Skip to content

Commit af1401b

Browse files
authored
Refactor + add tests (#5)
1 parent e9417e2 commit af1401b

12 files changed

Lines changed: 90 additions & 30 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,6 @@ jobs:
2828

2929
- name: Build CLI (test)
3030
run: bun run build:cli
31+
32+
- name: Run tests
33+
run: bun run test

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"lint": "biome lint",
3030
"format": "biome check --write --linter-enabled=false",
3131
"build:app": "bun run -F './apps/registry' build",
32-
"build:cli": "bun run -F './packages/usts' build"
32+
"build:cli": "bun run -F './packages/usts' build",
33+
"test": "bun run -F './packages/usts' test"
3334
},
3435
"devDependencies": {
3536
"@biomejs/biome": "2.3.11",

packages/usts/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"license": "MIT",
77
"scripts": {
88
"build": "bunx --bun tsdown",
9-
"prepublishOnly": "bun run build"
9+
"prepublishOnly": "bun run build",
10+
"test": "bun test"
1011
},
1112
"repository": {
1213
"type": "git",

packages/usts/src/config/schema.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ const UserscriptMetaHeaderConfigSchema: z.ZodObject<{
6161
>
6262
>;
6363
require: z.ZodOptional<z.ZodArray<z.ZodString>>;
64-
resource: z.ZodOptional<
65-
z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>
66-
>;
64+
resource: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
6765
grant: z.ZodOptional<z.ZodArray<z.ZodString>>;
6866
downloadURL: z.ZodOptional<z.ZodString>;
6967
updateURL: z.ZodOptional<z.ZodString>;
@@ -88,7 +86,7 @@ const UserscriptMetaHeaderConfigSchema: z.ZodObject<{
8886
),
8987

9088
require: z.optional(z.array(z.string())),
91-
resource: z.optional(z.union([z.string(), z.array(z.string())])),
89+
resource: z.optional(z.record(z.string(), z.string())),
9290

9391
grant: z.optional(z.array(z.string())),
9492

packages/usts/src/core/build/build.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ const USERSCRIPT_OUTPUT_FILE_NAME = "index.user.js";
1111

1212
async function buildUserscript(
1313
config: ResolvedUserscriptConfig,
14-
): Promise<void> {
14+
options?: { write?: boolean },
15+
): Promise<string> {
1516
console.log("\n⚒️ Building userscript");
1617

17-
const header = serializeMetaHeader(config.header).serializedHeader;
18+
const header = serializeMetaHeader(config.header);
1819

1920
const bundle = await rolldown({ input: config.entryPoint, tsconfig: true });
2021
const result = await bundle.generate({
@@ -28,7 +29,11 @@ async function buildUserscript(
2829
}
2930

3031
const bundledCode = result.output[0].code;
31-
const fullCode = `${header}\n\n${bundledCode}` as const;
32+
const fullCode = `${header}\n\n${bundledCode}`;
33+
34+
if (!options?.write) {
35+
return fullCode;
36+
}
3237

3338
const outDir = config.outDir;
3439
if (config.clean) {
@@ -39,6 +44,8 @@ async function buildUserscript(
3944
const outFile = path.join(outDir, USERSCRIPT_OUTPUT_FILE_NAME);
4045
await fs.writeFile(outFile, fullCode, "utf-8");
4146
console.log("\n🎉 Build process complete!");
47+
48+
return fullCode;
4249
}
4350

4451
export { buildUserscript };

packages/usts/src/core/build/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ export default async function build(): Promise<void> {
1212
);
1313
}
1414

15-
await buildUserscript(userscriptConfig);
15+
await buildUserscript(userscriptConfig, { write: true });
1616
}

packages/usts/src/core/build/meta-header.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,39 @@ import type { UserscriptMetaHeaderConfig } from "~/config/schema";
33
const headerStart = "// ==UserScript==" as const;
44
const headerEnd = "// ==/UserScript==" as const;
55

6-
type HeaderLine = `// @${string}`;
7-
8-
function getHeaderLine(key: string, val: string | boolean): HeaderLine {
6+
function getHeaderLine(
7+
key: string,
8+
val: string | boolean | readonly [string, string],
9+
) {
910
if (typeof val === "boolean") return `// @${key}`;
1011
const paddedKey = key.padEnd(16);
11-
return `// @${paddedKey} ${val}`;
12+
if (typeof val === "string") return `// @${paddedKey} ${val}`;
13+
const paddedSubKey = val[0].padEnd(8);
14+
return `// @${paddedKey} ${paddedSubKey} ${val[1]}`;
1215
}
1316

1417
function getHeaderLines(
1518
key: string,
16-
val: string | string[] | boolean,
17-
): HeaderLine[] {
19+
val: string | string[] | boolean | Record<string, string>,
20+
) {
1821
if (Array.isArray(val)) return val.map((v) => getHeaderLine(key, v));
1922
if (typeof val === "string") return [getHeaderLine(key, val)];
2023
if (typeof val === "boolean") return [getHeaderLine(key, val)];
24+
if (typeof val === "object") {
25+
return Object.entries(val).map((v) => getHeaderLine(key, v));
26+
}
2127
throw new Error(`Unknown header value type: ${typeof val}`);
2228
}
2329

24-
type SerializeMetaHeader = `// ==UserScript==
25-
${string}
26-
// ==/UserScript==`;
27-
28-
interface SerializeMetaHeaderResult {
29-
serializedHeader: SerializeMetaHeader;
30-
}
31-
3230
export function serializeMetaHeader(
3331
headerConfig: UserscriptMetaHeaderConfig,
34-
): SerializeMetaHeaderResult {
32+
): string {
3533
const headerConfigEntries = Object.entries(headerConfig);
36-
const headerLines = headerConfigEntries.flatMap(([key, val]) =>
37-
getHeaderLines(key, val),
34+
const headerLines = headerConfigEntries.flatMap(([kwy, val]) =>
35+
getHeaderLines(kwy, val),
3836
);
3937
const serializedHeaderLines = headerLines.join("\n");
4038
const serializedHeader =
4139
`${headerStart}\n${serializedHeaderLines}\n${headerEnd}` as const;
42-
return { serializedHeader };
40+
return serializedHeader;
4341
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
2+
3+
exports[`Basic userscript Correctly bundles a basic userscript 1`] = `
4+
"// ==UserScript==
5+
// @name Userscript name
6+
// @namespace fixtures
7+
// @match https://example.com/*
8+
// @version 1.0.0
9+
// @description Userscript description
10+
// ==/UserScript==
11+
12+
(function() {
13+
console.log("Hello world!");
14+
})();
15+
"
16+
`;

packages/usts/tests/basic.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { describe, expect, it } from "bun:test";
2+
3+
import { buildUserscript } from "../src/core/build/build";
4+
import { resolveFixture } from "./helpers/resolve";
5+
6+
describe("Basic userscript", () => {
7+
it("Correctly bundles a basic userscript", async () => {
8+
const fixture = resolveFixture("fixtures/basic/index.ts");
9+
const result = await buildUserscript(fixture);
10+
expect(result).toMatchSnapshot();
11+
});
12+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log("Hello world!");

0 commit comments

Comments
 (0)