@di-framework/cli 0.0.0-prerelease.100

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/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @di-framework/cli
2
+
3
+ This package contains the CLI tools and scripts used for managing the `@di-framework` monorepo.
4
+
5
+ ## Usage
6
+
7
+ The CLI acts as a proxy to run various commands defined in the `cmd` directory.
8
+
9
+ ### Global Installation (Recommended)
10
+
11
+ You can make the CLI available globally on your system as the `di-framework` command by linking it:
12
+
13
+ ```bash
14
+ cd packages/bin
15
+ bun link
16
+ ```
17
+
18
+ Then you can run commands from anywhere:
19
+
20
+ ```bash
21
+ di-framework <command> [args...]
22
+ ```
23
+
24
+ ### Running Directly
25
+
26
+ Alternatively, you can run it directly using Bun from the root of the repository:
27
+
28
+ ```bash
29
+ bun run packages/bin/main.ts <command> [args...]
30
+ ```
31
+
32
+ ### Available Commands
33
+
34
+ * **`build`**: Builds the packages in the monorepo (`di-framework`, `di-framework-repo`, `di-framework-http`). It cleans the `dist` directories and runs `tsc`.
35
+ ```bash
36
+ bun run packages/bin/main.ts build
37
+ ```
38
+
39
+ * **`typecheck`**: Runs TypeScript type checking across the packages to ensure type safety without emitting compiled files.
40
+ ```bash
41
+ bun run packages/bin/main.ts typecheck
42
+ ```
43
+
44
+ * **`publish`**: Publishes the built packages to the npm registry.
45
+ ```bash
46
+ bun run packages/bin/main.ts publish
47
+ ```
48
+
49
+ ## Adding New Commands
50
+
51
+ To add a new command, simply create a new TypeScript file in the `packages/bin/cmd/` directory. The name of the file (without the `.ts` extension) will become the command name.
package/cmd/build.ts ADDED
@@ -0,0 +1,48 @@
1
+ import { $ } from "bun";
2
+ import { join } from "path";
3
+ import { readFileSync, writeFileSync, existsSync } from "fs";
4
+
5
+ export const PACKAGES = ["packages/di-framework", "packages/di-framework-repo", "packages/di-framework-http", "packages/bin"];
6
+
7
+ export async function build() {
8
+ console.log("๐Ÿš€ Starting build process...");
9
+
10
+ const rootPkgPath = join(process.cwd(), "package.json");
11
+ const rootPkg = JSON.parse(readFileSync(rootPkgPath, "utf-8"));
12
+ const version = rootPkg.version;
13
+ console.log(`๐Ÿ“Œ Using version ${version} from workspace root`);
14
+
15
+ for (const pkgDir of PACKAGES) {
16
+ console.log(`\n๐Ÿ“ฆ Building ${pkgDir}...`);
17
+ const fullPath = join(process.cwd(), pkgDir);
18
+
19
+ // Sync version
20
+ const pkgJsonPath = join(fullPath, "package.json");
21
+ if (existsSync(pkgJsonPath)) {
22
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
23
+ writeFileSync(pkgJsonPath, JSON.stringify({ name: pkgJson.name, version, ...pkgJson }, null, 2) + "\n");
24
+ }
25
+
26
+ // 1. Clean dist
27
+ await $`rm -rf ${join(fullPath, "dist")}`;
28
+
29
+ // 2. Run build
30
+ console.log(" Running build...");
31
+ if (existsSync(join(fullPath, "tsconfig.build.json"))) {
32
+ await $`cd ${fullPath} && bun x tsc -p tsconfig.build.json`;
33
+ } else {
34
+ await $`cd ${fullPath} && bun run build`;
35
+ }
36
+
37
+ console.log(` โœ… Finished building ${pkgDir}`);
38
+ }
39
+
40
+ console.log("\nโœจ All builds completed successfully!");
41
+ }
42
+
43
+ if (import.meta.main || !Bun.isMainThread) {
44
+ build().catch((err) => {
45
+ console.error("โŒ Build failed:", err);
46
+ process.exit(1);
47
+ });
48
+ }
package/cmd/publish.ts ADDED
@@ -0,0 +1,43 @@
1
+ import { $ } from "bun";
2
+ import { join } from "path";
3
+
4
+ export const PACKAGES = ["packages/di-framework", "packages/di-framework-repo", "packages/di-framework-http", "packages/bin"];
5
+
6
+ export async function publish() {
7
+ // 1. Run tests
8
+ console.log("๐Ÿงช Running tests...");
9
+ for (const pkgDir of PACKAGES) {
10
+ await $`bun test ${pkgDir}`;
11
+ }
12
+
13
+ // 2. Build
14
+ console.log("๐Ÿ—๏ธ Building packages...");
15
+ await $`bun run packages/bin/cmd/build.ts`;
16
+
17
+ // 3. Publish
18
+ for (const pkgDir of PACKAGES) {
19
+ const fullPath = join(process.cwd(), pkgDir);
20
+ const pkgJson = await import(join(fullPath, "package.json"));
21
+
22
+ console.log(`\n๐Ÿšข Publishing ${pkgJson.name}@${pkgJson.version}...`);
23
+
24
+ // Using --access public for scoped packages
25
+ // We use npm publish or bun publish. Bun publish is fine.
26
+ try {
27
+ await $`cd ${fullPath} && bun publish --access public`;
28
+ console.log(` โœ… Published ${pkgJson.name}`);
29
+ } catch (err) {
30
+ console.error(` โŒ Failed to publish ${pkgJson.name}:`, err);
31
+ // Depending on needs, we might want to continue or stop
32
+ }
33
+ }
34
+
35
+ console.log("\n๐Ÿ Publish process finished!");
36
+ }
37
+
38
+ if (import.meta.main || !Bun.isMainThread) {
39
+ publish().catch((err) => {
40
+ console.error("โŒ Publish script failed:", err);
41
+ process.exit(1);
42
+ });
43
+ }
package/cmd/test.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { $ } from "bun";
2
+ import { join } from "path";
3
+
4
+ export const SCRIPT_PATH = join(import.meta.dir, "..", "scripts", "e2e-test.sh");
5
+ export const REPO_ROOT = join(import.meta.dir, "..", "..", "..");
6
+
7
+ export async function test() {
8
+ await $`bash ${SCRIPT_PATH}`.cwd(REPO_ROOT).env(process.env);
9
+ }
10
+
11
+ if (import.meta.main || !Bun.isMainThread) {
12
+ test().catch((err) => {
13
+ console.error("โŒ Tests failed:", err);
14
+ process.exit(1);
15
+ });
16
+ }
@@ -0,0 +1,52 @@
1
+ import { $ } from "bun";
2
+ import { join } from "path";
3
+ import { existsSync } from "fs";
4
+
5
+ export const PACKAGES = ["packages/di-framework", "packages/di-framework-repo", "packages/di-framework-http", "packages/bin"];
6
+
7
+ export async function typecheck() {
8
+ console.log("๐Ÿš€ Starting typecheck process...");
9
+
10
+ let hasError = false;
11
+
12
+ for (const pkgDir of PACKAGES) {
13
+ console.log(`\n๐Ÿ“ฆ Typechecking ${pkgDir}...`);
14
+ const fullPath = join(process.cwd(), pkgDir);
15
+
16
+ if (existsSync(join(fullPath, "tsconfig.build.json"))) {
17
+ try {
18
+ console.log(" Running typecheck...");
19
+ await $`cd ${fullPath} && bun x tsc -p tsconfig.build.json --noEmit`;
20
+ console.log(` โœ… Passed typecheck for ${pkgDir}`);
21
+ } catch (err) {
22
+ console.error(` โŒ Typecheck failed for ${pkgDir}`);
23
+ hasError = true;
24
+ }
25
+ } else if (existsSync(join(fullPath, "tsconfig.json"))) {
26
+ try {
27
+ console.log(" Running typecheck...");
28
+ await $`cd ${fullPath} && bun x tsc --noEmit`;
29
+ console.log(` โœ… Passed typecheck for ${pkgDir}`);
30
+ } catch (err) {
31
+ console.error(` โŒ Typecheck failed for ${pkgDir}`);
32
+ hasError = true;
33
+ }
34
+ } else {
35
+ console.warn(` โš ๏ธ No tsconfig.json found in ${pkgDir}`);
36
+ }
37
+ }
38
+
39
+ if (hasError) {
40
+ console.log("\nโŒ Typecheck failed for some packages!");
41
+ process.exit(1);
42
+ } else {
43
+ console.log("\nโœจ All packages passed typecheck successfully!");
44
+ }
45
+ }
46
+
47
+ if (import.meta.main || !Bun.isMainThread) {
48
+ typecheck().catch((err) => {
49
+ console.error("โŒ Typecheck failed with an unexpected error:", err);
50
+ process.exit(1);
51
+ });
52
+ }
package/main.ts ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env bun
2
+ import { join } from "path";
3
+
4
+ const COMMANDS: Record<string, string> = {
5
+ build: "Builds the packages in the monorepo",
6
+ test: "Runs the E2E test suite",
7
+ typecheck: "Runs TypeScript type checking across the packages",
8
+ publish: "Publishes the built packages to the npm registry",
9
+ };
10
+
11
+ async function main() {
12
+ const args = process.argv.slice(2);
13
+ const cmdName = args[0];
14
+
15
+ if (!cmdName) {
16
+ console.error("Please provide a command\n");
17
+ console.error("Available commands:");
18
+ for (const [name, desc] of Object.entries(COMMANDS)) {
19
+ console.error(` ${name.padEnd(12)} ${desc}`);
20
+ }
21
+ process.exit(1);
22
+ }
23
+
24
+ if (!(cmdName in COMMANDS)) {
25
+ console.error(`Unknown command: ${cmdName}`);
26
+ process.exit(1);
27
+ }
28
+
29
+ const cmdFile = join(import.meta.dir, "cmd", `${cmdName}.ts`);
30
+
31
+ const worker = new Worker(cmdFile, { env: process.env });
32
+
33
+ await new Promise<void>((resolve, reject) => {
34
+ worker.addEventListener("close", () => resolve());
35
+ worker.addEventListener("error", (e) => reject(e));
36
+ });
37
+ }
38
+
39
+ main().catch((err) => {
40
+ console.error("Failed to execute command:", err.message ?? err);
41
+ process.exit(1);
42
+ });
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@di-framework/cli",
3
+ "version": "0.0.0-prerelease.100",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "main.ts",
7
+ "bin": {
8
+ "di-framework": "dist/di-framework"
9
+ },
10
+ "scripts": {
11
+ "build": "bun build --compile main.ts --outfile=./dist/di-framework",
12
+ "postinstall": "bun run build"
13
+ },
14
+ "devDependencies": {
15
+ "@types/bun": "latest"
16
+ },
17
+ "peerDependencies": {
18
+ "typescript": "^5"
19
+ }
20
+ }
@@ -0,0 +1,119 @@
1
+ #!/bin/bash
2
+
3
+ # End-to-End Test Script for DI Framework
4
+ # Tests the entire project including compilation, unit tests, and example validation
5
+
6
+ echo "================================"
7
+ echo "DI Framework E2E Test Suite"
8
+ echo "================================"
9
+ echo ""
10
+
11
+ # Color codes for output
12
+ RED='\033[0;31m'
13
+ GREEN='\033[0;32m'
14
+ YELLOW='\033[1;33m'
15
+ NC='\033[0m' # No Color
16
+
17
+ # Test counter
18
+ TESTS_PASSED=0
19
+ TESTS_FAILED=0
20
+
21
+ # Function to print test status
22
+ print_test() {
23
+ echo -e "${YELLOW}โ–ถ $1${NC}"
24
+ }
25
+
26
+ print_success() {
27
+ echo -e "${GREEN}โœ“ $1${NC}"
28
+ ((TESTS_PASSED++))
29
+ }
30
+
31
+ print_error() {
32
+ echo -e "${RED}โœ— $1${NC}"
33
+ ((TESTS_FAILED++))
34
+ }
35
+
36
+ # 1. Check dependencies
37
+ print_test "Checking environment..."
38
+ if ! type bun > /dev/null 2>&1; then
39
+ print_error "Bun is not installed. Please install Bun: https://bun.sh"
40
+ exit 1
41
+ fi
42
+ print_success "Bun is installed"
43
+
44
+ if ! type node > /dev/null 2>&1; then
45
+ print_error "Node.js is not installed. Please install Node.js"
46
+ exit 1
47
+ fi
48
+ print_success "Node.js is installed"
49
+
50
+ echo ""
51
+
52
+ # 2. Install dependencies
53
+ print_test "Installing dependencies..."
54
+ if bun install --frozen-lockfile 2>/dev/null || bun install; then
55
+ print_success "Dependencies installed"
56
+ else
57
+ print_error "Failed to install dependencies"
58
+ exit 1
59
+ fi
60
+
61
+ echo ""
62
+
63
+ # 3. TypeScript type checking (per-package)
64
+ print_test "Running TypeScript type checks..."
65
+ if npx tsc --noEmit -p packages/di-framework/tsconfig.json 2>/dev/null; then
66
+ print_success "di-framework type checks passed"
67
+ else
68
+ print_error "di-framework type checks failed"
69
+ npx tsc --noEmit -p packages/di-framework/tsconfig.json 2>&1 | head -20
70
+ exit 1
71
+ fi
72
+
73
+ echo ""
74
+
75
+ # 4. Run framework tests
76
+ print_test "Running DI framework unit tests..."
77
+ if (cd packages/di-framework && bun test); then
78
+ print_success "Framework unit tests passed"
79
+ else
80
+ print_error "Framework unit tests failed"
81
+ exit 1
82
+ fi
83
+
84
+ echo ""
85
+
86
+ # 5. Validate examples compile
87
+ print_test "Validating example code..."
88
+ if npx tsc --noEmit -p packages/examples/tsconfig.json 2>/dev/null; then
89
+ print_success "Advanced example validated"
90
+ else
91
+ print_error "Advanced example has type errors"
92
+ fi
93
+
94
+ echo ""
95
+
96
+ # 6. Check if examples package is properly structured
97
+ print_test "Checking examples package structure..."
98
+ if [ -f "packages/examples/package.json" ]; then
99
+ print_success "Examples package.json found"
100
+ else
101
+ print_error "Examples package.json not found"
102
+ fi
103
+
104
+ echo ""
105
+
106
+ # Summary
107
+ echo "================================"
108
+ echo "Test Summary"
109
+ echo "================================"
110
+ echo -e "${GREEN}Passed: $TESTS_PASSED${NC}"
111
+ if [ $TESTS_FAILED -gt 0 ]; then
112
+ echo -e "${RED}Failed: $TESTS_FAILED${NC}"
113
+ exit 1
114
+ else
115
+ echo -e "${GREEN}Failed: 0${NC}"
116
+ echo ""
117
+ echo -e "${GREEN}All tests passed! โœ“${NC}"
118
+ exit 0
119
+ fi
@@ -0,0 +1,69 @@
1
+ import { describe, it, expect } from "bun:test";
2
+ import { join } from "path";
3
+ import { existsSync, readFileSync, writeFileSync, mkdtempSync, rmSync } from "fs";
4
+ import { tmpdir } from "os";
5
+ import { PACKAGES } from "../cmd/build";
6
+
7
+ const REPO_ROOT = join(import.meta.dir, "..", "..", "..");
8
+
9
+ describe("build command", () => {
10
+ describe("PACKAGES", () => {
11
+ it("includes all expected packages", () => {
12
+ expect(PACKAGES).toContain("packages/di-framework");
13
+ expect(PACKAGES).toContain("packages/di-framework-repo");
14
+ expect(PACKAGES).toContain("packages/di-framework-http");
15
+ expect(PACKAGES).toContain("packages/bin");
16
+ });
17
+
18
+ it("every package directory exists", () => {
19
+ for (const pkg of PACKAGES) {
20
+ const fullPath = join(REPO_ROOT, pkg);
21
+ expect(existsSync(fullPath)).toBe(true);
22
+ }
23
+ });
24
+
25
+ it("every package has a package.json", () => {
26
+ for (const pkg of PACKAGES) {
27
+ const pkgJsonPath = join(REPO_ROOT, pkg, "package.json");
28
+ expect(existsSync(pkgJsonPath)).toBe(true);
29
+ }
30
+ });
31
+ });
32
+
33
+ describe("version sync", () => {
34
+ it("syncs the root version into a package.json", () => {
35
+ const tmp = mkdtempSync(join(tmpdir(), "build-test-"));
36
+ try {
37
+ const fakePkg = { name: "test-pkg", version: "0.0.0" };
38
+ const pkgPath = join(tmp, "package.json");
39
+ writeFileSync(pkgPath, JSON.stringify(fakePkg));
40
+
41
+ // Simulate what build() does for version sync
42
+ const rootPkg = JSON.parse(readFileSync(join(REPO_ROOT, "package.json"), "utf-8"));
43
+ const pkgJson = JSON.parse(readFileSync(pkgPath, "utf-8"));
44
+ pkgJson.version = rootPkg.version;
45
+ writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2) + "\n");
46
+
47
+ const result = JSON.parse(readFileSync(pkgPath, "utf-8"));
48
+ expect(result.version).toBe(rootPkg.version);
49
+ expect(result.name).toBe("test-pkg");
50
+ } finally {
51
+ rmSync(tmp, { recursive: true });
52
+ }
53
+ });
54
+ });
55
+
56
+ describe("build configs", () => {
57
+ it("every package has a tsconfig.json or tsconfig.build.json or a build script", () => {
58
+ for (const pkg of PACKAGES) {
59
+ const fullPath = join(REPO_ROOT, pkg);
60
+ const hasTsconfigBuild = existsSync(join(fullPath, "tsconfig.build.json"));
61
+ const hasTsconfig = existsSync(join(fullPath, "tsconfig.json"));
62
+ const pkgJson = JSON.parse(readFileSync(join(fullPath, "package.json"), "utf-8"));
63
+ const hasBuildScript = !!pkgJson.scripts?.build;
64
+
65
+ expect(hasTsconfigBuild || hasTsconfig || hasBuildScript).toBe(true);
66
+ }
67
+ });
68
+ });
69
+ });
@@ -0,0 +1,78 @@
1
+ import { describe, it, expect } from "bun:test";
2
+ import { join } from "path";
3
+ import { existsSync, readFileSync } from "fs";
4
+ import { PACKAGES } from "../cmd/publish";
5
+
6
+ const REPO_ROOT = join(import.meta.dir, "..", "..", "..");
7
+
8
+ describe("publish command", () => {
9
+ describe("PACKAGES", () => {
10
+ it("includes all expected packages", () => {
11
+ expect(PACKAGES).toContain("packages/di-framework");
12
+ expect(PACKAGES).toContain("packages/di-framework-repo");
13
+ expect(PACKAGES).toContain("packages/di-framework-http");
14
+ expect(PACKAGES).toContain("packages/bin");
15
+ });
16
+
17
+ it("matches the build command PACKAGES list", async () => {
18
+ const { PACKAGES: BUILD_PACKAGES } = await import("../cmd/build");
19
+ expect(PACKAGES).toEqual(BUILD_PACKAGES);
20
+ });
21
+
22
+ it("every package directory exists", () => {
23
+ for (const pkg of PACKAGES) {
24
+ expect(existsSync(join(REPO_ROOT, pkg))).toBe(true);
25
+ }
26
+ });
27
+ });
28
+
29
+ describe("package metadata", () => {
30
+ it("every package has a name", () => {
31
+ for (const pkg of PACKAGES) {
32
+ const pkgJson = JSON.parse(readFileSync(join(REPO_ROOT, pkg, "package.json"), "utf-8"));
33
+ expect(pkgJson.name).toBeDefined();
34
+ expect(typeof pkgJson.name).toBe("string");
35
+ expect(pkgJson.name.length).toBeGreaterThan(0);
36
+ }
37
+ });
38
+
39
+ it("every package has a version", () => {
40
+ for (const pkg of PACKAGES) {
41
+ const pkgJson = JSON.parse(readFileSync(join(REPO_ROOT, pkg, "package.json"), "utf-8"));
42
+ expect(pkgJson.version).toBeDefined();
43
+ expect(typeof pkgJson.version).toBe("string");
44
+ }
45
+ });
46
+
47
+ it("no package is marked as private (publishable)", () => {
48
+ for (const pkg of PACKAGES) {
49
+ const pkgJson = JSON.parse(readFileSync(join(REPO_ROOT, pkg, "package.json"), "utf-8"));
50
+ expect(pkgJson.private).not.toBe(true);
51
+ }
52
+ });
53
+
54
+ it("scoped packages use the @di-framework scope", () => {
55
+ for (const pkg of PACKAGES) {
56
+ const pkgJson = JSON.parse(readFileSync(join(REPO_ROOT, pkg, "package.json"), "utf-8"));
57
+ if (pkgJson.name.startsWith("@")) {
58
+ expect(pkgJson.name).toMatch(/^@di-framework\//);
59
+ }
60
+ }
61
+ });
62
+ });
63
+
64
+ describe("publish pipeline order", () => {
65
+ it("runs tests before build in the source", () => {
66
+ const source = readFileSync(join(import.meta.dir, "..", "cmd", "publish.ts"), "utf-8");
67
+ const testIndex = source.indexOf("bun test");
68
+ const buildIndex = source.indexOf("bun run packages/bin/cmd/build.ts");
69
+ const publishIndex = source.indexOf("bun publish");
70
+
71
+ expect(testIndex).toBeGreaterThan(-1);
72
+ expect(buildIndex).toBeGreaterThan(-1);
73
+ expect(publishIndex).toBeGreaterThan(-1);
74
+ expect(testIndex).toBeLessThan(buildIndex);
75
+ expect(buildIndex).toBeLessThan(publishIndex);
76
+ });
77
+ });
78
+ });
@@ -0,0 +1,47 @@
1
+ import { describe, it, expect } from "bun:test";
2
+ import { existsSync, readFileSync } from "fs";
3
+ import { join } from "path";
4
+ import { SCRIPT_PATH, REPO_ROOT } from "../cmd/test";
5
+
6
+ describe("test command", () => {
7
+ describe("paths", () => {
8
+ it("e2e script exists at the resolved path", () => {
9
+ expect(existsSync(SCRIPT_PATH)).toBe(true);
10
+ });
11
+
12
+ it("e2e script is a bash script", () => {
13
+ const content = readFileSync(SCRIPT_PATH, "utf-8");
14
+ expect(content.startsWith("#!/bin/bash")).toBe(true);
15
+ });
16
+
17
+ it("repo root contains package.json", () => {
18
+ expect(existsSync(join(REPO_ROOT, "package.json"))).toBe(true);
19
+ });
20
+
21
+ it("repo root contains the packages directory", () => {
22
+ expect(existsSync(join(REPO_ROOT, "packages"))).toBe(true);
23
+ });
24
+ });
25
+
26
+ describe("e2e script content", () => {
27
+ it("runs type checks", () => {
28
+ const content = readFileSync(SCRIPT_PATH, "utf-8");
29
+ expect(content).toContain("TypeScript type check");
30
+ });
31
+
32
+ it("runs unit tests", () => {
33
+ const content = readFileSync(SCRIPT_PATH, "utf-8");
34
+ expect(content).toContain("bun test");
35
+ });
36
+
37
+ it("validates examples", () => {
38
+ const content = readFileSync(SCRIPT_PATH, "utf-8");
39
+ expect(content).toContain("Validating example code");
40
+ });
41
+
42
+ it("reports a summary", () => {
43
+ const content = readFileSync(SCRIPT_PATH, "utf-8");
44
+ expect(content).toContain("Test Summary");
45
+ });
46
+ });
47
+ });
@@ -0,0 +1,58 @@
1
+ import { describe, it, expect } from "bun:test";
2
+ import { join } from "path";
3
+ import { existsSync } from "fs";
4
+ import { PACKAGES } from "../cmd/typecheck";
5
+
6
+ const REPO_ROOT = join(import.meta.dir, "..", "..", "..");
7
+
8
+ describe("typecheck command", () => {
9
+ describe("PACKAGES", () => {
10
+ it("includes all expected packages", () => {
11
+ expect(PACKAGES).toContain("packages/di-framework");
12
+ expect(PACKAGES).toContain("packages/di-framework-repo");
13
+ expect(PACKAGES).toContain("packages/di-framework-http");
14
+ expect(PACKAGES).toContain("packages/bin");
15
+ });
16
+
17
+ it("every package directory exists", () => {
18
+ for (const pkg of PACKAGES) {
19
+ expect(existsSync(join(REPO_ROOT, pkg))).toBe(true);
20
+ }
21
+ });
22
+ });
23
+
24
+ describe("tsconfig detection", () => {
25
+ it("every package has a tsconfig.json or tsconfig.build.json", () => {
26
+ for (const pkg of PACKAGES) {
27
+ const fullPath = join(REPO_ROOT, pkg);
28
+ const hasBuild = existsSync(join(fullPath, "tsconfig.build.json"));
29
+ const hasBase = existsSync(join(fullPath, "tsconfig.json"));
30
+ expect(hasBuild || hasBase).toBe(true);
31
+ }
32
+ });
33
+
34
+ it("prefers tsconfig.build.json when present", () => {
35
+ for (const pkg of PACKAGES) {
36
+ const fullPath = join(REPO_ROOT, pkg);
37
+ const hasBuild = existsSync(join(fullPath, "tsconfig.build.json"));
38
+ const hasBase = existsSync(join(fullPath, "tsconfig.json"));
39
+
40
+ // At minimum one must exist; if both exist, build takes priority
41
+ // (verified by reading the typecheck command logic)
42
+ if (hasBuild) {
43
+ // tsconfig.build.json is used โ€” this is the preferred path
44
+ expect(hasBuild).toBe(true);
45
+ } else {
46
+ expect(hasBase).toBe(true);
47
+ }
48
+ }
49
+ });
50
+ });
51
+
52
+ describe("package consistency", () => {
53
+ it("matches the build command PACKAGES list", async () => {
54
+ const { PACKAGES: BUILD_PACKAGES } = await import("../cmd/build");
55
+ expect(PACKAGES).toEqual(BUILD_PACKAGES);
56
+ });
57
+ });
58
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Environment setup & latest features
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "ESNext",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+
11
+ // Bundler mode
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "noEmit": true,
16
+
17
+ // Best practices
18
+ "strict": true,
19
+ "skipLibCheck": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "noUncheckedIndexedAccess": true,
22
+
23
+ // Some stricter flags (disabled by default)
24
+ "noUnusedLocals": false,
25
+ "noUnusedParameters": false,
26
+ "noPropertyAccessFromIndexSignature": false
27
+ }
28
+ }