@akanjs/devkit 1.0.19 → 2.1.0-rc.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 (194) hide show
  1. package/aiEditor.ts +304 -0
  2. package/akanApp/akanApp.host.ts +393 -0
  3. package/akanApp/index.ts +1 -0
  4. package/akanConfig/akanConfig.test.ts +236 -0
  5. package/akanConfig/akanConfig.ts +384 -0
  6. package/akanConfig/index.ts +2 -0
  7. package/akanConfig/types.ts +23 -0
  8. package/applicationBuildReporter.ts +69 -0
  9. package/applicationBuildRunner.ts +302 -0
  10. package/applicationReleasePackager.ts +206 -0
  11. package/artifact/implicitRootLayout.ts +155 -0
  12. package/artifact/index.ts +1 -0
  13. package/artifact/routeSeedIndex.test.ts +98 -0
  14. package/artifact/routeSeedIndex.ts +130 -0
  15. package/auth.ts +41 -0
  16. package/builder.ts +164 -0
  17. package/capacitor.base.config.ts +88 -0
  18. package/capacitorApp.ts +440 -0
  19. package/commandDecorators/argMeta.ts +102 -0
  20. package/commandDecorators/command.ts +343 -0
  21. package/commandDecorators/commandBuilder.ts +224 -0
  22. package/commandDecorators/commandDecorators.test.ts +212 -0
  23. package/commandDecorators/commandMeta.ts +7 -0
  24. package/commandDecorators/dependencyBuilder.ts +100 -0
  25. package/{esm/src/commandDecorators/helpFormatter.js → commandDecorators/helpFormatter.ts} +100 -47
  26. package/{esm/src/commandDecorators/index.js → commandDecorators/index.ts} +4 -2
  27. package/commandDecorators/targetMeta.ts +31 -0
  28. package/commandDecorators/types.ts +10 -0
  29. package/constants.ts +25 -0
  30. package/createTunnel.ts +36 -0
  31. package/dependencyScanner.ts +357 -0
  32. package/devkitUtils.test.ts +259 -0
  33. package/executors.test.ts +315 -0
  34. package/executors.ts +1390 -0
  35. package/{esm/src/extractDeps.js → extractDeps.ts} +26 -20
  36. package/{esm/src/fileEditor.js → fileEditor.ts} +51 -32
  37. package/fileSys.ts +39 -0
  38. package/frontendBuild/allRoutesBuilder.ts +103 -0
  39. package/frontendBuild/buildRouteClient.test.ts +190 -0
  40. package/frontendBuild/clientBuildTypes.ts +114 -0
  41. package/frontendBuild/clientEntriesBundler.ts +303 -0
  42. package/frontendBuild/clientEntryDiscovery.ts +199 -0
  43. package/frontendBuild/csrArtifactBuilder.ts +237 -0
  44. package/frontendBuild/cssCompiler.ts +286 -0
  45. package/frontendBuild/cssImportResolver.ts +116 -0
  46. package/frontendBuild/fontOptimizer.ts +427 -0
  47. package/frontendBuild/frontendBuild.test.ts +204 -0
  48. package/frontendBuild/hmrChangeClassifier.ts +28 -0
  49. package/frontendBuild/hmrWatcher.ts +102 -0
  50. package/frontendBuild/index.ts +18 -0
  51. package/frontendBuild/pagesBundleBuilder.ts +137 -0
  52. package/frontendBuild/pagesEntrySourceGenerator.ts +37 -0
  53. package/frontendBuild/precompressArtifacts.ts +59 -0
  54. package/frontendBuild/routeClientBuilder.ts +290 -0
  55. package/frontendBuild/routesManifestArtifactSerializer.ts +62 -0
  56. package/frontendBuild/ssrBaseArtifactBuilder.ts +139 -0
  57. package/frontendBuild/vendorSpecifiers.ts +16 -0
  58. package/frontendBuild/watchRootResolver.ts +28 -0
  59. package/getCredentials.ts +19 -0
  60. package/getDirname.ts +3 -0
  61. package/getModelFileData.ts +59 -0
  62. package/getRelatedCnsts.ts +313 -0
  63. package/guideline.ts +19 -0
  64. package/incrementalBuilder/incrementalBuilder.host.test.ts +51 -0
  65. package/incrementalBuilder/incrementalBuilder.host.ts +152 -0
  66. package/incrementalBuilder/incrementalBuilder.proc.ts +331 -0
  67. package/incrementalBuilder/index.ts +1 -0
  68. package/{esm/src/index.js → index.ts} +28 -15
  69. package/lint/no-deep-internal-import.grit +25 -0
  70. package/lint/no-import-client-functions.grit +32 -0
  71. package/lint/no-import-external-library.grit +21 -0
  72. package/lint/no-js-private-class-method.grit +42 -0
  73. package/lint/no-use-client-in-server.grit +7 -0
  74. package/lint/non-scalar-props-restricted.grit +13 -0
  75. package/linter.ts +271 -0
  76. package/mobile/index.ts +1 -0
  77. package/mobile/mobileTarget.test.ts +53 -0
  78. package/mobile/mobileTarget.ts +88 -0
  79. package/package.json +48 -31
  80. package/prompter.ts +72 -0
  81. package/scanInfo.ts +606 -0
  82. package/selectModel.ts +11 -0
  83. package/{esm/src/spinner.js → spinner.ts} +22 -28
  84. package/{esm/src/capacitorApp.js → src/capacitorApp.ts} +82 -81
  85. package/sshTunnel.ts +152 -0
  86. package/{esm/src/streamAi.js → streamAi.ts} +18 -12
  87. package/transforms/barrelAnalyzer.ts +278 -0
  88. package/transforms/barrelImportsPlugin.ts +504 -0
  89. package/transforms/externalizeFrameworkPlugin.ts +185 -0
  90. package/transforms/index.ts +5 -0
  91. package/transforms/rscUseClientTransform.ts +59 -0
  92. package/transforms/transforms.test.ts +208 -0
  93. package/transforms/useClientBundlePlugin.ts +47 -0
  94. package/tsconfig.json +37 -0
  95. package/typeChecker.ts +264 -0
  96. package/types.ts +44 -0
  97. package/ui/MultiScrollList.tsx +242 -0
  98. package/ui/ScrollList.tsx +107 -0
  99. package/ui/index.ts +2 -0
  100. package/{esm/src/uploadRelease.js → uploadRelease.ts} +50 -34
  101. package/{esm/src/useStdoutDimensions.js → useStdoutDimensions.ts} +5 -5
  102. package/README.md +0 -1
  103. package/cjs/index.js +0 -21
  104. package/cjs/src/aiEditor.js +0 -311
  105. package/cjs/src/auth.js +0 -72
  106. package/cjs/src/builder.js +0 -114
  107. package/cjs/src/capacitorApp.js +0 -313
  108. package/cjs/src/commandDecorators/argMeta.js +0 -88
  109. package/cjs/src/commandDecorators/command.js +0 -324
  110. package/cjs/src/commandDecorators/commandMeta.js +0 -30
  111. package/cjs/src/commandDecorators/helpFormatter.js +0 -211
  112. package/cjs/src/commandDecorators/index.js +0 -31
  113. package/cjs/src/commandDecorators/targetMeta.js +0 -57
  114. package/cjs/src/commandDecorators/types.js +0 -15
  115. package/cjs/src/constants.js +0 -46
  116. package/cjs/src/createTunnel.js +0 -49
  117. package/cjs/src/dependencyScanner.js +0 -220
  118. package/cjs/src/executors.js +0 -964
  119. package/cjs/src/extractDeps.js +0 -103
  120. package/cjs/src/fileEditor.js +0 -120
  121. package/cjs/src/getCredentials.js +0 -44
  122. package/cjs/src/getDirname.js +0 -38
  123. package/cjs/src/getModelFileData.js +0 -66
  124. package/cjs/src/getRelatedCnsts.js +0 -260
  125. package/cjs/src/guideline.js +0 -15
  126. package/cjs/src/index.js +0 -65
  127. package/cjs/src/linter.js +0 -238
  128. package/cjs/src/prompter.js +0 -85
  129. package/cjs/src/scanInfo.js +0 -491
  130. package/cjs/src/selectModel.js +0 -46
  131. package/cjs/src/spinner.js +0 -93
  132. package/cjs/src/streamAi.js +0 -62
  133. package/cjs/src/typeChecker.js +0 -207
  134. package/cjs/src/types.js +0 -15
  135. package/cjs/src/uploadRelease.js +0 -112
  136. package/cjs/src/useStdoutDimensions.js +0 -43
  137. package/esm/index.js +0 -1
  138. package/esm/src/aiEditor.js +0 -282
  139. package/esm/src/auth.js +0 -42
  140. package/esm/src/builder.js +0 -81
  141. package/esm/src/commandDecorators/argMeta.js +0 -54
  142. package/esm/src/commandDecorators/command.js +0 -290
  143. package/esm/src/commandDecorators/commandMeta.js +0 -7
  144. package/esm/src/commandDecorators/targetMeta.js +0 -33
  145. package/esm/src/commandDecorators/types.js +0 -0
  146. package/esm/src/constants.js +0 -17
  147. package/esm/src/createTunnel.js +0 -26
  148. package/esm/src/dependencyScanner.js +0 -187
  149. package/esm/src/executors.js +0 -928
  150. package/esm/src/getCredentials.js +0 -11
  151. package/esm/src/getDirname.js +0 -5
  152. package/esm/src/getModelFileData.js +0 -33
  153. package/esm/src/getRelatedCnsts.js +0 -221
  154. package/esm/src/guideline.js +0 -0
  155. package/esm/src/linter.js +0 -205
  156. package/esm/src/prompter.js +0 -51
  157. package/esm/src/scanInfo.js +0 -455
  158. package/esm/src/selectModel.js +0 -13
  159. package/esm/src/typeChecker.js +0 -174
  160. package/esm/src/types.js +0 -0
  161. package/index.d.ts +0 -1
  162. package/src/aiEditor.d.ts +0 -50
  163. package/src/auth.d.ts +0 -9
  164. package/src/builder.d.ts +0 -18
  165. package/src/capacitorApp.d.ts +0 -39
  166. package/src/commandDecorators/argMeta.d.ts +0 -67
  167. package/src/commandDecorators/command.d.ts +0 -2
  168. package/src/commandDecorators/commandMeta.d.ts +0 -2
  169. package/src/commandDecorators/helpFormatter.d.ts +0 -3
  170. package/src/commandDecorators/index.d.ts +0 -6
  171. package/src/commandDecorators/targetMeta.d.ts +0 -19
  172. package/src/commandDecorators/types.d.ts +0 -1
  173. package/src/constants.d.ts +0 -26
  174. package/src/createTunnel.d.ts +0 -8
  175. package/src/dependencyScanner.d.ts +0 -23
  176. package/src/executors.d.ts +0 -296
  177. package/src/extractDeps.d.ts +0 -7
  178. package/src/fileEditor.d.ts +0 -16
  179. package/src/getCredentials.d.ts +0 -12
  180. package/src/getDirname.d.ts +0 -1
  181. package/src/getModelFileData.d.ts +0 -16
  182. package/src/getRelatedCnsts.d.ts +0 -53
  183. package/src/guideline.d.ts +0 -19
  184. package/src/index.d.ts +0 -23
  185. package/src/linter.d.ts +0 -109
  186. package/src/prompter.d.ts +0 -14
  187. package/src/scanInfo.d.ts +0 -82
  188. package/src/selectModel.d.ts +0 -1
  189. package/src/spinner.d.ts +0 -20
  190. package/src/streamAi.d.ts +0 -6
  191. package/src/typeChecker.d.ts +0 -52
  192. package/src/types.d.ts +0 -31
  193. package/src/uploadRelease.d.ts +0 -10
  194. package/src/useStdoutDimensions.d.ts +0 -1
@@ -0,0 +1,315 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2
+ import { mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { AkanAppConfig } from "./akanConfig";
6
+ import { AppExecutor, Executor, PkgExecutor, WorkspaceExecutor } from "./executors";
7
+ import { AppInfo } from "./scanInfo";
8
+ import type { PackageJson } from "./types";
9
+
10
+ const originalEnv = { ...process.env };
11
+ const tempRoots: string[] = [];
12
+
13
+ const makeTempRoot = async () => {
14
+ const root = await mkdtemp(path.join(os.tmpdir(), "akan-devkit-"));
15
+ tempRoots.push(root);
16
+ return root;
17
+ };
18
+
19
+ const writeJson = async (filePath: string, value: object) => {
20
+ await mkdir(path.dirname(filePath), { recursive: true });
21
+ await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`);
22
+ };
23
+
24
+ const rootPackageJson = (extra: Partial<PackageJson> = {}): PackageJson => ({
25
+ name: "fixture",
26
+ version: "1.0.0",
27
+ description: "fixture",
28
+ dependencies: {
29
+ react: "19.0.0",
30
+ "react-dom": "19.0.0",
31
+ "react-server-dom-webpack": "19.0.0",
32
+ sharp: "1.0.0",
33
+ lodash: "4.0.0",
34
+ },
35
+ devDependencies: {
36
+ typescript: "6.0.0",
37
+ },
38
+ ...extra,
39
+ });
40
+
41
+ beforeEach(() => {
42
+ process.env = { ...originalEnv };
43
+ });
44
+
45
+ afterEach(async () => {
46
+ process.env = { ...originalEnv };
47
+ await Promise.all(tempRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
48
+ });
49
+
50
+ describe("Executor filesystem helpers", () => {
51
+ test("resolves paths and reads/writes files relative to cwd", async () => {
52
+ const root = await makeTempRoot();
53
+ const exec = new Executor("fixture", root);
54
+
55
+ expect(exec.getPath("nested/file.txt")).toBe(path.join(root, "nested/file.txt"));
56
+ expect(exec.getPath("./relative.txt")).toBe(path.join(root, "relative.txt"));
57
+ expect(exec.getPath(root)).toBe(root);
58
+
59
+ await exec.mkdir("nested");
60
+ await exec.writeFile("nested/file.txt", "hello");
61
+ await exec.writeJson("nested/data.json", { ok: true });
62
+
63
+ expect(await exec.exists("nested/file.txt")).toBe(true);
64
+ expect(await exec.readFile("nested/file.txt")).toBe("hello");
65
+ expect(await exec.readJson("nested/data.json")).toEqual({ ok: true });
66
+ expect(await exec.readdir("nested")).toEqual(expect.arrayContaining(["file.txt", "data.json"]));
67
+
68
+ const entries = await exec.getFilesAndDirs(".");
69
+ expect(entries.dirs).toContain("nested");
70
+ });
71
+
72
+ test("applies CLI template files with dictionary replacement and overwrite control", async () => {
73
+ const root = await makeTempRoot();
74
+ const exec = new Executor("fixture", root);
75
+
76
+ const [created] = await exec.applyTemplate({
77
+ basePath: "local",
78
+ template: "localDev/docker-compose.yaml.template",
79
+ dict: { repoName: "sample" },
80
+ });
81
+ expect(created?.filePath).toBe(path.join(root, "local/docker-compose.yaml"));
82
+ expect(await readFile(path.join(root, "local/docker-compose.yaml"), "utf8")).toContain("sample-network");
83
+
84
+ await writeFile(path.join(root, "local/docker-compose.yaml"), "custom");
85
+ await exec.applyTemplate({
86
+ basePath: "local",
87
+ template: "localDev/docker-compose.yaml.template",
88
+ dict: { repoName: "changed" },
89
+ overwrite: false,
90
+ });
91
+ expect(await readFile(path.join(root, "local/docker-compose.yaml"), "utf8")).toBe("custom");
92
+ });
93
+
94
+ test("applies hidden files and directories from CLI templates", async () => {
95
+ const root = await makeTempRoot();
96
+ const exec = new Executor("fixture", root);
97
+
98
+ await exec.applyTemplate({
99
+ basePath: "workspace",
100
+ template: "workspaceRoot",
101
+ dict: { repoName: "sample", appName: "demo", serveDomain: "localhost" },
102
+ });
103
+
104
+ expect(await readFile(path.join(root, "workspace/.gitignore"), "utf8")).toContain("node_modules");
105
+ expect(await readFile(path.join(root, "workspace/.env"), "utf8")).toContain("AKAN_PUBLIC_REPO_NAME");
106
+ expect(await readFile(path.join(root, "workspace/.vscode/settings.json"), "utf8")).toContain("typescript.tsdk");
107
+ expect(await readFile(path.join(root, "workspace/biome.json"), "utf8")).toContain(
108
+ "./node_modules/@akanjs/devkit/lint/no-import-client-functions.grit",
109
+ );
110
+ });
111
+
112
+ test("copies static files from CLI templates", async () => {
113
+ const root = await makeTempRoot();
114
+ const exec = new Executor("fixture", root);
115
+
116
+ await exec.applyTemplate({
117
+ basePath: "app",
118
+ template: "app",
119
+ dict: { appName: "demo", companyName: "fixture", startDomain: "localhost" },
120
+ options: { libs: [] },
121
+ });
122
+
123
+ const templateRoot = path.resolve(import.meta.dir, "../cli/templates/app/public");
124
+ await expect(readFile(path.join(root, "app/public/logo.png"))).resolves.toEqual(
125
+ await readFile(path.join(templateRoot, "logo.png")),
126
+ );
127
+ await expect(readFile(path.join(root, "app/public/favicon.ico"))).resolves.toEqual(
128
+ await readFile(path.join(templateRoot, "favicon.ico")),
129
+ );
130
+ });
131
+ });
132
+
133
+ describe("Workspace and app executor environment contracts", () => {
134
+ test("reads base development environment and reports required missing values", () => {
135
+ process.env.AKAN_PUBLIC_REPO_NAME = "repo";
136
+ process.env.AKAN_PUBLIC_SERVE_DOMAIN = "example.com";
137
+ process.env.AKAN_PUBLIC_ENV = "local";
138
+ process.env.AKAN_PUBLIC_APP_NAME = "demo";
139
+ process.env.AKAN_WORKSPACE_ROOT = "/workspace";
140
+ process.env.PORT_OFFSET = "10";
141
+
142
+ expect(WorkspaceExecutor.getBaseDevEnv()).toEqual({
143
+ appName: "demo",
144
+ workspaceRoot: "/workspace",
145
+ repoName: "repo",
146
+ serveDomain: "example.com",
147
+ env: "local",
148
+ portOffset: 10,
149
+ });
150
+
151
+ delete process.env.AKAN_PUBLIC_REPO_NAME;
152
+ expect(() => WorkspaceExecutor.getBaseDevEnv()).toThrow("AKAN_PUBLIC_REPO_NAME is not set");
153
+ });
154
+
155
+ test("reads base development environment from an explicit env file", async () => {
156
+ const root = await makeTempRoot();
157
+ await writeFile(
158
+ path.join(root, ".env"),
159
+ [
160
+ "AKAN_PUBLIC_REPO_NAME=file-repo",
161
+ 'AKAN_PUBLIC_SERVE_DOMAIN="file.example.com"',
162
+ "AKAN_PUBLIC_ENV=develop",
163
+ "AKAN_WORKSPACE_ROOT=/from-file",
164
+ "AKAN_PUBLIC_APP_NAME=file-app",
165
+ "PORT_OFFSET=7",
166
+ "",
167
+ ].join("\n"),
168
+ );
169
+ delete process.env.AKAN_PUBLIC_REPO_NAME;
170
+ delete process.env.AKAN_PUBLIC_SERVE_DOMAIN;
171
+
172
+ expect(WorkspaceExecutor.getBaseDevEnv(path.join(root, ".env"))).toEqual({
173
+ appName: "file-app",
174
+ workspaceRoot: "/from-file",
175
+ repoName: "file-repo",
176
+ serveDomain: "file.example.com",
177
+ env: "develop",
178
+ portOffset: 7,
179
+ });
180
+ });
181
+
182
+ test("builds app command environment and prepareCommand artifacts", async () => {
183
+ const root = await makeTempRoot();
184
+ process.env.AKAN_PUBLIC_REPO_NAME = "repo";
185
+ process.env.AKAN_PUBLIC_SERVE_DOMAIN = "example.com";
186
+ process.env.AKAN_PUBLIC_ENV = "local";
187
+ process.env.PORT_OFFSET = "3";
188
+
189
+ await writeJson(path.join(root, "package.json"), rootPackageJson());
190
+ await mkdir(path.join(root, "apps/demo/private"), { recursive: true });
191
+ await mkdir(path.join(root, "apps/demo/public"), { recursive: true });
192
+ await writeFile(
193
+ path.join(root, "apps/demo/akan.config.ts"),
194
+ [
195
+ "export default {",
196
+ ' routes: [{ basePath: "admin", domains: { debug: ["Admin.Debug.Example.com:8282"] } }],',
197
+ ' i18n: { locales: ["en", "ko"], defaultLocale: "ko" },',
198
+ "};",
199
+ "",
200
+ ].join("\n"),
201
+ );
202
+
203
+ const workspace = new WorkspaceExecutor({ workspaceRoot: root, repoName: "repo" });
204
+ const app = AppExecutor.from(workspace, "demo");
205
+ const env = app.getCommandEnv({ EXTRA: "ok" });
206
+ expect(env.AKAN_PUBLIC_APP_NAME).toBe("demo");
207
+ expect(env.AKAN_WORKSPACE_ROOT).toBe(root);
208
+ expect(env.PORT).toBe("8285");
209
+ expect(env.AKAN_PUBLIC_CLIENT_PORT).toBe("8285");
210
+ expect(env.AKAN_PUBLIC_SERVER_PORT).toBe("8285");
211
+ expect(env.EXTRA).toBe("ok");
212
+
213
+ const prepared = await app.prepareCommand("build");
214
+ expect(prepared.env.AKAN_COMMAND_TYPE).toBe("build");
215
+ expect(prepared.env.AKAN_PUBLIC_BASE_PATHS).toBe("admin");
216
+ expect((await stat(path.join(root, "dist/apps/demo/private"))).isDirectory()).toBe(true);
217
+ expect((await stat(path.join(root, "dist/apps/demo/public"))).isDirectory()).toBe(true);
218
+ });
219
+ });
220
+
221
+ describe("PkgExecutor package generation", () => {
222
+ test("generates dist package metadata from root dependency versions", async () => {
223
+ const root = await makeTempRoot();
224
+ await writeJson(path.join(root, "package.json"), rootPackageJson());
225
+ await writeJson(path.join(root, "pkgs/@sample/tool/package.json"), {
226
+ name: "@sample/tool",
227
+ version: "0.1.0",
228
+ description: "tool",
229
+ exports: { "./extra": { import: "./extra.ts" } },
230
+ peerDependencies: { react: "19.0.0" },
231
+ peerDependenciesMeta: { react: { optional: true } },
232
+ optionalDependencies: { sharp: "1.0.0" },
233
+ });
234
+
235
+ const workspace = new WorkspaceExecutor({ workspaceRoot: root, repoName: "repo" });
236
+ const pkg = PkgExecutor.from(workspace, "@sample/tool");
237
+ const distPackageJson = await pkg.generateDistPackageJson(["lodash"], ["typescript"]);
238
+
239
+ expect(distPackageJson).toMatchObject({
240
+ name: "@sample/tool",
241
+ type: "module",
242
+ engines: { bun: ">=1.3.13" },
243
+ dependencies: { lodash: "4.0.0" },
244
+ devDependencies: { typescript: "6.0.0" },
245
+ peerDependencies: { react: "19.0.0" },
246
+ peerDependenciesMeta: { react: { optional: true } },
247
+ optionalDependencies: { sharp: "1.0.0" },
248
+ });
249
+ expect(distPackageJson.exports?.["."]).toEqual({
250
+ import: "./index.ts",
251
+ types: "./index.ts",
252
+ default: "./index.ts",
253
+ });
254
+ expect(await Bun.file(path.join(root, "dist/pkgs/@sample/tool/package.json")).json()).toEqual(distPackageJson);
255
+ expect(await Bun.file(path.join(root, "pkgs/@sample/tool/package.json")).json()).toEqual(distPackageJson);
256
+ });
257
+ });
258
+
259
+ describe("scan info construction", () => {
260
+ test("indexes database, service, and scalar file conventions from prepared scan results", () => {
261
+ const root = "/workspace";
262
+ const workspace = new WorkspaceExecutor({ workspaceRoot: root, repoName: "repo" });
263
+ const app = AppExecutor.from(workspace, "demo");
264
+ const config = new AkanAppConfig(
265
+ app,
266
+ [],
267
+ rootPackageJson(),
268
+ {},
269
+ {
270
+ repoName: "repo",
271
+ serveDomain: "example.com",
272
+ env: "debug",
273
+ portOffset: 0,
274
+ workspaceRoot: root,
275
+ },
276
+ );
277
+
278
+ const info = new AppInfo(
279
+ app,
280
+ {
281
+ name: "demo",
282
+ type: "app",
283
+ repoName: "repo",
284
+ serveDomain: "example.com",
285
+ akanConfig: config,
286
+ files: {
287
+ constant: { databases: ["post"], scalars: ["money"] },
288
+ dictionary: { databases: ["post"], services: ["auth"], scalars: ["money"] },
289
+ document: { databases: ["post"], scalars: ["money"] },
290
+ service: { databases: ["post"], services: ["auth"] },
291
+ signal: { databases: ["post"], services: ["auth"] },
292
+ store: { databases: [], services: [] },
293
+ template: { databases: [], services: [], scalars: [] },
294
+ unit: { databases: [], services: [], scalars: [] },
295
+ util: { databases: [], services: [], scalars: [] },
296
+ view: { databases: [], services: [], scalars: [] },
297
+ zone: { databases: [], services: [], scalars: [] },
298
+ },
299
+ libDeps: [],
300
+ pkgDeps: [],
301
+ dependencies: [],
302
+ devDependencies: [],
303
+ routes: ["./_index.tsx"],
304
+ },
305
+ [],
306
+ );
307
+
308
+ expect(info.getDatabaseModules()).toEqual(["post"]);
309
+ expect(info.getServiceModules()).toEqual(["auth"]);
310
+ expect(info.getScalarModules()).toEqual(["money"]);
311
+ expect(info.file.constant.databases.has("post")).toBe(true);
312
+ expect(info.file.dictionary.services.has("auth")).toBe(true);
313
+ expect(info.file.document.scalars.has("money")).toBe(true);
314
+ });
315
+ });