rtfct 0.1.0

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.
Files changed (39) hide show
  1. package/.project/adrs/001-use-bun-typescript.md +52 -0
  2. package/.project/guardrails.md +65 -0
  3. package/.project/kanban/backlog.md +7 -0
  4. package/.project/kanban/done.md +240 -0
  5. package/.project/kanban/in-progress.md +11 -0
  6. package/.project/kickstart.md +63 -0
  7. package/.project/protocol.md +134 -0
  8. package/.project/specs/requirements.md +152 -0
  9. package/.project/testing/strategy.md +123 -0
  10. package/.project/theology.md +125 -0
  11. package/CLAUDE.md +119 -0
  12. package/README.md +143 -0
  13. package/package.json +31 -0
  14. package/src/args.ts +104 -0
  15. package/src/commands/add.ts +78 -0
  16. package/src/commands/init.ts +128 -0
  17. package/src/commands/praise.ts +19 -0
  18. package/src/commands/regenerate.ts +122 -0
  19. package/src/commands/status.ts +163 -0
  20. package/src/help.ts +52 -0
  21. package/src/index.ts +102 -0
  22. package/src/kanban.ts +83 -0
  23. package/src/manifest.ts +67 -0
  24. package/src/presets/base.ts +195 -0
  25. package/src/presets/elixir.ts +118 -0
  26. package/src/presets/github.ts +194 -0
  27. package/src/presets/index.ts +154 -0
  28. package/src/presets/typescript.ts +589 -0
  29. package/src/presets/zig.ts +494 -0
  30. package/tests/integration/add.test.ts +104 -0
  31. package/tests/integration/init.test.ts +197 -0
  32. package/tests/integration/praise.test.ts +36 -0
  33. package/tests/integration/regenerate.test.ts +154 -0
  34. package/tests/integration/status.test.ts +165 -0
  35. package/tests/unit/args.test.ts +144 -0
  36. package/tests/unit/kanban.test.ts +162 -0
  37. package/tests/unit/manifest.test.ts +155 -0
  38. package/tests/unit/presets.test.ts +295 -0
  39. package/tsconfig.json +19 -0
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Unit Tests for the Kanban Parser
3
+ */
4
+
5
+ import { describe, test, expect } from "bun:test";
6
+ import {
7
+ countTasks,
8
+ extractCurrentTask,
9
+ parseKanbanFile,
10
+ formatRelativeTime,
11
+ } from "../../src/kanban";
12
+
13
+ describe("countTasks", () => {
14
+ test("counts zero tasks in empty content", () => {
15
+ expect(countTasks("# Backlog\n\nNo tasks here.")).toBe(0);
16
+ });
17
+
18
+ test("counts single task", () => {
19
+ const content = `# Backlog
20
+
21
+ ## [TASK-001] First Task
22
+
23
+ Description here.
24
+ `;
25
+ expect(countTasks(content)).toBe(1);
26
+ });
27
+
28
+ test("counts multiple tasks", () => {
29
+ const content = `# Backlog
30
+
31
+ ## [TASK-001] First Task
32
+
33
+ Description.
34
+
35
+ ## [TASK-002] Second Task
36
+
37
+ Another description.
38
+
39
+ ## [TASK-003] Third Task
40
+
41
+ Yet another.
42
+ `;
43
+ expect(countTasks(content)).toBe(3);
44
+ });
45
+
46
+ test("ignores non-task headers", () => {
47
+ const content = `# Backlog
48
+
49
+ ## [TASK-001] Real Task
50
+
51
+ ## Not a Task
52
+
53
+ ## [OTHER-002] Also Not a Task
54
+ `;
55
+ expect(countTasks(content)).toBe(1);
56
+ });
57
+ });
58
+
59
+ describe("extractCurrentTask", () => {
60
+ test("returns null for empty content", () => {
61
+ expect(extractCurrentTask("# In Progress\n\nNo tasks.")).toBeNull();
62
+ });
63
+
64
+ test("extracts task from content", () => {
65
+ const content = `# In Progress
66
+
67
+ ## [TASK-004] Implement user auth
68
+
69
+ Description here.
70
+ `;
71
+ const task = extractCurrentTask(content);
72
+ expect(task).not.toBeNull();
73
+ expect(task!.id).toBe("TASK-004");
74
+ expect(task!.title).toBe("Implement user auth");
75
+ });
76
+
77
+ test("extracts first task when multiple exist", () => {
78
+ const content = `# In Progress
79
+
80
+ ## [TASK-001] First
81
+
82
+ ## [TASK-002] Second
83
+ `;
84
+ const task = extractCurrentTask(content);
85
+ expect(task!.id).toBe("TASK-001");
86
+ expect(task!.title).toBe("First");
87
+ });
88
+ });
89
+
90
+ describe("parseKanbanFile", () => {
91
+ test("parses backlog file", () => {
92
+ const content = `# Backlog
93
+
94
+ ## [TASK-001] First
95
+
96
+ ## [TASK-002] Second
97
+ `;
98
+ const result = parseKanbanFile(content, "backlog");
99
+ expect(result.count).toBe(2);
100
+ expect(result.currentTask).toBeNull();
101
+ });
102
+
103
+ test("parses in-progress file with current task", () => {
104
+ const content = `# In Progress
105
+
106
+ ## [TASK-003] Current Work
107
+ `;
108
+ const result = parseKanbanFile(content, "in-progress");
109
+ expect(result.count).toBe(1);
110
+ expect(result.currentTask).not.toBeNull();
111
+ expect(result.currentTask!.id).toBe("TASK-003");
112
+ });
113
+
114
+ test("parses done file", () => {
115
+ const content = `# Done
116
+
117
+ ## [TASK-001] First Completed
118
+
119
+ ## [TASK-002] Second Completed
120
+ `;
121
+ const result = parseKanbanFile(content, "done");
122
+ expect(result.count).toBe(2);
123
+ expect(result.currentTask).toBeNull();
124
+ });
125
+ });
126
+
127
+ describe("formatRelativeTime", () => {
128
+ test("formats just now", () => {
129
+ const now = new Date();
130
+ expect(formatRelativeTime(now)).toBe("just now");
131
+ });
132
+
133
+ test("formats minutes ago", () => {
134
+ const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
135
+ expect(formatRelativeTime(fiveMinutesAgo)).toBe("5 minutes ago");
136
+ });
137
+
138
+ test("formats single minute", () => {
139
+ const oneMinuteAgo = new Date(Date.now() - 1 * 60 * 1000);
140
+ expect(formatRelativeTime(oneMinuteAgo)).toBe("1 minute ago");
141
+ });
142
+
143
+ test("formats hours ago", () => {
144
+ const threeHoursAgo = new Date(Date.now() - 3 * 60 * 60 * 1000);
145
+ expect(formatRelativeTime(threeHoursAgo)).toBe("3 hours ago");
146
+ });
147
+
148
+ test("formats single hour", () => {
149
+ const oneHourAgo = new Date(Date.now() - 1 * 60 * 60 * 1000);
150
+ expect(formatRelativeTime(oneHourAgo)).toBe("1 hour ago");
151
+ });
152
+
153
+ test("formats days ago", () => {
154
+ const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000);
155
+ expect(formatRelativeTime(twoDaysAgo)).toBe("2 days ago");
156
+ });
157
+
158
+ test("formats single day", () => {
159
+ const oneDayAgo = new Date(Date.now() - 1 * 24 * 60 * 60 * 1000);
160
+ expect(formatRelativeTime(oneDayAgo)).toBe("1 day ago");
161
+ });
162
+ });
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Unit Tests for the Manifest Reader
3
+ */
4
+
5
+ import { describe, test, expect, beforeEach, afterEach } from "bun:test";
6
+ import { mkdir, writeFile, rm } from "fs/promises";
7
+ import { join } from "path";
8
+ import { collectGeneratedPaths, readManifest } from "../../src/manifest";
9
+
10
+ describe("readManifest", () => {
11
+ const testDir = "/tmp/rtfct-manifest-test";
12
+
13
+ beforeEach(async () => {
14
+ await mkdir(testDir, { recursive: true });
15
+ });
16
+
17
+ afterEach(async () => {
18
+ await rm(testDir, { recursive: true, force: true });
19
+ });
20
+
21
+ test("reads valid manifest", async () => {
22
+ const manifest = {
23
+ name: "test",
24
+ version: "1.0.0",
25
+ description: "Test preset",
26
+ generated_paths: ["src/", "lib/"],
27
+ };
28
+ await writeFile(join(testDir, "manifest.json"), JSON.stringify(manifest));
29
+
30
+ const result = await readManifest(testDir);
31
+ expect(result).not.toBeNull();
32
+ expect(result!.name).toBe("test");
33
+ expect(result!.generated_paths).toEqual(["src/", "lib/"]);
34
+ });
35
+
36
+ test("returns null for missing manifest", async () => {
37
+ const result = await readManifest(testDir);
38
+ expect(result).toBeNull();
39
+ });
40
+
41
+ test("returns null for invalid JSON", async () => {
42
+ await writeFile(join(testDir, "manifest.json"), "not valid json");
43
+
44
+ const result = await readManifest(testDir);
45
+ expect(result).toBeNull();
46
+ });
47
+ });
48
+
49
+ describe("collectGeneratedPaths", () => {
50
+ const testDir = "/tmp/rtfct-collect-test";
51
+ const presetsDir = join(testDir, ".project", "presets");
52
+
53
+ beforeEach(async () => {
54
+ await mkdir(presetsDir, { recursive: true });
55
+ });
56
+
57
+ afterEach(async () => {
58
+ await rm(testDir, { recursive: true, force: true });
59
+ });
60
+
61
+ test("returns default paths when no presets exist", async () => {
62
+ // Empty presets directory
63
+ const paths = await collectGeneratedPaths(testDir);
64
+ expect(paths).toEqual(["src/", "tests/"]);
65
+ });
66
+
67
+ test("collects paths from single preset", async () => {
68
+ const presetDir = join(presetsDir, "zig");
69
+ await mkdir(presetDir);
70
+ await writeFile(
71
+ join(presetDir, "manifest.json"),
72
+ JSON.stringify({
73
+ name: "zig",
74
+ version: "1.0.0",
75
+ description: "Zig preset",
76
+ generated_paths: ["src/", "build.zig"],
77
+ })
78
+ );
79
+
80
+ const paths = await collectGeneratedPaths(testDir);
81
+ expect(paths).toContain("src/");
82
+ expect(paths).toContain("build.zig");
83
+ });
84
+
85
+ test("collects paths from multiple presets", async () => {
86
+ // Create zig preset
87
+ const zigDir = join(presetsDir, "zig");
88
+ await mkdir(zigDir);
89
+ await writeFile(
90
+ join(zigDir, "manifest.json"),
91
+ JSON.stringify({
92
+ name: "zig",
93
+ version: "1.0.0",
94
+ description: "Zig",
95
+ generated_paths: ["src/", "build.zig"],
96
+ })
97
+ );
98
+
99
+ // Create typescript preset
100
+ const tsDir = join(presetsDir, "typescript");
101
+ await mkdir(tsDir);
102
+ await writeFile(
103
+ join(tsDir, "manifest.json"),
104
+ JSON.stringify({
105
+ name: "typescript",
106
+ version: "1.0.0",
107
+ description: "TypeScript",
108
+ generated_paths: ["src/", "tests/"],
109
+ })
110
+ );
111
+
112
+ const paths = await collectGeneratedPaths(testDir);
113
+ expect(paths).toContain("src/");
114
+ expect(paths).toContain("build.zig");
115
+ expect(paths).toContain("tests/");
116
+ });
117
+
118
+ test("deduplicates paths from multiple presets", async () => {
119
+ // Both presets have src/
120
+ const zigDir = join(presetsDir, "zig");
121
+ await mkdir(zigDir);
122
+ await writeFile(
123
+ join(zigDir, "manifest.json"),
124
+ JSON.stringify({
125
+ name: "zig",
126
+ version: "1.0.0",
127
+ description: "Zig",
128
+ generated_paths: ["src/"],
129
+ })
130
+ );
131
+
132
+ const tsDir = join(presetsDir, "typescript");
133
+ await mkdir(tsDir);
134
+ await writeFile(
135
+ join(tsDir, "manifest.json"),
136
+ JSON.stringify({
137
+ name: "typescript",
138
+ version: "1.0.0",
139
+ description: "TypeScript",
140
+ generated_paths: ["src/"],
141
+ })
142
+ );
143
+
144
+ const paths = await collectGeneratedPaths(testDir);
145
+ // Should only have src/ once
146
+ const srcCount = paths.filter((p) => p === "src/").length;
147
+ expect(srcCount).toBe(1);
148
+ });
149
+
150
+ test("returns default when presets directory does not exist", async () => {
151
+ await rm(presetsDir, { recursive: true, force: true });
152
+ const paths = await collectGeneratedPaths(testDir);
153
+ expect(paths).toEqual(["src/", "tests/"]);
154
+ });
155
+ });
@@ -0,0 +1,295 @@
1
+ /**
2
+ * Unit Tests for the Preset System
3
+ */
4
+
5
+ import { describe, test, expect, beforeEach, afterEach } from "bun:test";
6
+ import { mkdir, rm, stat } from "fs/promises";
7
+ import { join } from "path";
8
+ import {
9
+ resolvePreset,
10
+ resolvePresetSync,
11
+ writePreset,
12
+ isPresetInstalled,
13
+ BASE_PRESET,
14
+ } from "../../src/presets";
15
+ import { ZIG_PRESET } from "../../src/presets/zig";
16
+ import { TYPESCRIPT_PRESET } from "../../src/presets/typescript";
17
+ import { ELIXIR_PRESET } from "../../src/presets/elixir";
18
+ import { parseGitHubRef } from "../../src/presets/github";
19
+
20
+ describe("resolvePresetSync", () => {
21
+ test("resolves base preset", () => {
22
+ const result = resolvePresetSync("base");
23
+ expect(result.success).toBe(true);
24
+ if (result.success) {
25
+ expect(result.preset.name).toBe("base");
26
+ }
27
+ });
28
+
29
+ test("resolves zig preset", () => {
30
+ const result = resolvePresetSync("zig");
31
+ expect(result.success).toBe(true);
32
+ if (result.success) {
33
+ expect(result.preset.name).toBe("zig");
34
+ }
35
+ });
36
+
37
+ test("resolves typescript preset", () => {
38
+ const result = resolvePresetSync("typescript");
39
+ expect(result.success).toBe(true);
40
+ if (result.success) {
41
+ expect(result.preset.name).toBe("typescript");
42
+ }
43
+ });
44
+
45
+ test("resolves elixir preset", () => {
46
+ const result = resolvePresetSync("elixir");
47
+ expect(result.success).toBe(true);
48
+ if (result.success) {
49
+ expect(result.preset.name).toBe("elixir");
50
+ }
51
+ });
52
+
53
+ test("is case insensitive", () => {
54
+ const result = resolvePresetSync("ZIG");
55
+ expect(result.success).toBe(true);
56
+ });
57
+
58
+ test("returns error for unknown preset", () => {
59
+ const result = resolvePresetSync("unknown");
60
+ expect(result.success).toBe(false);
61
+ if (!result.success) {
62
+ expect(result.error).toContain("Unknown built-in preset");
63
+ }
64
+ });
65
+ });
66
+
67
+ describe("resolvePreset (async)", () => {
68
+ test("resolves built-in presets", async () => {
69
+ const result = await resolvePreset("base");
70
+ expect(result.success).toBe(true);
71
+ if (result.success) {
72
+ expect(result.preset.name).toBe("base");
73
+ }
74
+ });
75
+
76
+ test("is case insensitive", async () => {
77
+ const result = await resolvePreset("ZIG");
78
+ expect(result.success).toBe(true);
79
+ });
80
+
81
+ test("returns error for unknown preset", async () => {
82
+ const result = await resolvePreset("unknown");
83
+ expect(result.success).toBe(false);
84
+ if (!result.success) {
85
+ expect(result.error).toContain("Unknown preset");
86
+ }
87
+ });
88
+
89
+ test("returns error for local presets (not yet supported)", async () => {
90
+ const result = await resolvePreset("./local-preset");
91
+ expect(result.success).toBe(false);
92
+ if (!result.success) {
93
+ expect(result.error).toContain("Local presets not yet supported");
94
+ }
95
+ });
96
+
97
+ test("returns error for absolute local presets (not yet supported)", async () => {
98
+ const result = await resolvePreset("/absolute/path");
99
+ expect(result.success).toBe(false);
100
+ if (!result.success) {
101
+ expect(result.error).toContain("Local presets not yet supported");
102
+ }
103
+ });
104
+
105
+ test("attempts GitHub resolution for owner/repo format", async () => {
106
+ // This will fail because the repo doesn't exist, but it should attempt GitHub resolution
107
+ const result = await resolvePreset("nonexistent-owner/nonexistent-repo");
108
+ expect(result.success).toBe(false);
109
+ if (!result.success) {
110
+ // Should be a GitHub-related error, not "Unknown preset"
111
+ expect(result.error).toContain("nonexistent-owner/nonexistent-repo");
112
+ }
113
+ });
114
+ });
115
+
116
+ describe("parseGitHubRef", () => {
117
+ test("parses owner/repo format", () => {
118
+ const ref = parseGitHubRef("mattneel/rtfct-preset");
119
+ expect(ref).not.toBeNull();
120
+ expect(ref!.owner).toBe("mattneel");
121
+ expect(ref!.repo).toBe("rtfct-preset");
122
+ expect(ref!.ref).toBe("main");
123
+ });
124
+
125
+ test("parses owner/repo@branch format", () => {
126
+ const ref = parseGitHubRef("mattneel/rtfct-preset@develop");
127
+ expect(ref).not.toBeNull();
128
+ expect(ref!.owner).toBe("mattneel");
129
+ expect(ref!.repo).toBe("rtfct-preset");
130
+ expect(ref!.ref).toBe("develop");
131
+ });
132
+
133
+ test("parses owner/repo@tag format", () => {
134
+ const ref = parseGitHubRef("mattneel/rtfct-preset@v1.0.0");
135
+ expect(ref).not.toBeNull();
136
+ expect(ref!.owner).toBe("mattneel");
137
+ expect(ref!.repo).toBe("rtfct-preset");
138
+ expect(ref!.ref).toBe("v1.0.0");
139
+ });
140
+
141
+ test("returns null for invalid format (no slash)", () => {
142
+ const ref = parseGitHubRef("invalid");
143
+ expect(ref).toBeNull();
144
+ });
145
+
146
+ test("returns null for invalid format (empty owner)", () => {
147
+ const ref = parseGitHubRef("/repo");
148
+ expect(ref).toBeNull();
149
+ });
150
+
151
+ test("returns null for invalid format (empty repo)", () => {
152
+ const ref = parseGitHubRef("owner/");
153
+ expect(ref).toBeNull();
154
+ });
155
+
156
+ test("returns null for invalid format (empty branch)", () => {
157
+ const ref = parseGitHubRef("owner/repo@");
158
+ expect(ref).toBeNull();
159
+ });
160
+
161
+ test("returns null for too many slashes", () => {
162
+ const ref = parseGitHubRef("owner/repo/extra");
163
+ expect(ref).toBeNull();
164
+ });
165
+ });
166
+
167
+ describe("writePreset", () => {
168
+ const testDir = "/tmp/rtfct-preset-write-test";
169
+
170
+ beforeEach(async () => {
171
+ await mkdir(join(testDir, ".project", "presets"), { recursive: true });
172
+ });
173
+
174
+ afterEach(async () => {
175
+ await rm(testDir, { recursive: true, force: true });
176
+ });
177
+
178
+ test("writes preset files to project", async () => {
179
+ await writePreset(testDir, ZIG_PRESET);
180
+
181
+ const presetDir = join(testDir, ".project", "presets", "zig");
182
+ const stats = await stat(presetDir);
183
+ expect(stats.isDirectory()).toBe(true);
184
+
185
+ // Check manifest exists
186
+ const manifestStats = await stat(join(presetDir, "manifest.json"));
187
+ expect(manifestStats.isFile()).toBe(true);
188
+ });
189
+
190
+ test("writes all preset files", async () => {
191
+ await writePreset(testDir, ZIG_PRESET);
192
+
193
+ const presetDir = join(testDir, ".project", "presets", "zig");
194
+
195
+ // Check files exist
196
+ for (const file of ZIG_PRESET.files) {
197
+ const filePath = join(presetDir, file.path);
198
+ const stats = await stat(filePath);
199
+ expect(stats.isFile()).toBe(true);
200
+ }
201
+ });
202
+ });
203
+
204
+ describe("isPresetInstalled", () => {
205
+ const testDir = "/tmp/rtfct-preset-installed-test";
206
+
207
+ beforeEach(async () => {
208
+ await mkdir(join(testDir, ".project", "presets"), { recursive: true });
209
+ });
210
+
211
+ afterEach(async () => {
212
+ await rm(testDir, { recursive: true, force: true });
213
+ });
214
+
215
+ test("returns false when preset not installed", async () => {
216
+ const result = await isPresetInstalled(testDir, "zig");
217
+ expect(result).toBe(false);
218
+ });
219
+
220
+ test("returns true when preset is installed", async () => {
221
+ await writePreset(testDir, ZIG_PRESET);
222
+ const result = await isPresetInstalled(testDir, "zig");
223
+ expect(result).toBe(true);
224
+ });
225
+ });
226
+
227
+ describe("preset content", () => {
228
+ test("base preset has all Sacred Text files", () => {
229
+ expect(BASE_PRESET.files.length).toBeGreaterThan(0);
230
+ const paths = BASE_PRESET.files.map((f) => f.path);
231
+ expect(paths).toContain("protocol.md");
232
+ expect(paths).toContain("theology.md");
233
+ expect(paths).toContain("kickstart.md");
234
+ expect(paths).toContain("guardrails.md");
235
+ expect(paths).toContain("kanban/backlog.md");
236
+ expect(paths).toContain("kanban/in-progress.md");
237
+ expect(paths).toContain("kanban/done.md");
238
+ });
239
+
240
+ test("base preset has correct manifest", () => {
241
+ expect(BASE_PRESET.manifest.name).toBe("base");
242
+ expect(BASE_PRESET.manifest.version).toBe("0.1.0");
243
+ expect(BASE_PRESET.manifest.generated_paths).toContain("src/");
244
+ expect(BASE_PRESET.manifest.generated_paths).toContain("tests/");
245
+ });
246
+
247
+ test("zig preset has required files", () => {
248
+ expect(ZIG_PRESET.files.length).toBeGreaterThan(0);
249
+ const paths = ZIG_PRESET.files.map((f) => f.path);
250
+ expect(paths).toContain("testing/strategy.md");
251
+ expect(paths).toContain("guardrails.md");
252
+ expect(paths).toContain("design/patterns.md");
253
+ });
254
+
255
+ test("zig preset has build.zig in generated_paths", () => {
256
+ expect(ZIG_PRESET.manifest.generated_paths).toContain("build.zig");
257
+ expect(ZIG_PRESET.manifest.generated_paths).toContain("build.zig.zon");
258
+ });
259
+
260
+ test("zig preset depends on base", () => {
261
+ expect(ZIG_PRESET.manifest.depends).toContain("base");
262
+ });
263
+
264
+ test("typescript preset has required files", () => {
265
+ expect(TYPESCRIPT_PRESET.files.length).toBeGreaterThan(0);
266
+ const paths = TYPESCRIPT_PRESET.files.map((f) => f.path);
267
+ expect(paths).toContain("testing/strategy.md");
268
+ expect(paths).toContain("guardrails.md");
269
+ expect(paths).toContain("design/patterns.md");
270
+ });
271
+
272
+ test("typescript preset has dist in generated_paths", () => {
273
+ expect(TYPESCRIPT_PRESET.manifest.generated_paths).toContain("dist/");
274
+ });
275
+
276
+ test("typescript preset depends on base", () => {
277
+ expect(TYPESCRIPT_PRESET.manifest.depends).toContain("base");
278
+ });
279
+
280
+ test("elixir preset has required files", () => {
281
+ expect(ELIXIR_PRESET.files.length).toBeGreaterThan(0);
282
+ const paths = ELIXIR_PRESET.files.map((f) => f.path);
283
+ expect(paths).toContain("testing/strategy.md");
284
+ expect(paths).toContain("guardrails.md");
285
+ });
286
+
287
+ test("all presets have generated_paths", () => {
288
+ expect(BASE_PRESET.manifest.generated_paths.length).toBeGreaterThan(0);
289
+ expect(ZIG_PRESET.manifest.generated_paths.length).toBeGreaterThan(0);
290
+ expect(TYPESCRIPT_PRESET.manifest.generated_paths.length).toBeGreaterThan(
291
+ 0
292
+ );
293
+ expect(ELIXIR_PRESET.manifest.generated_paths.length).toBeGreaterThan(0);
294
+ });
295
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "skipLibCheck": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "allowSyntheticDefaultImports": true,
11
+ "resolveJsonModule": true,
12
+ "isolatedModules": true,
13
+ "verbatimModuleSyntax": true,
14
+ "lib": ["ESNext"],
15
+ "types": ["bun-types"]
16
+ },
17
+ "include": ["src/**/*", "tests/**/*"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }