@akanjs/devkit 3.0.0-alpha.51 → 3.0.0-alpha.53
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/CHANGELOG.md +15 -0
- package/artifact/implicitRootLayout.ts +2 -2
- package/executors.test.ts +58 -0
- package/executors.ts +3 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @akanjs/devkit
|
|
2
2
|
|
|
3
|
+
## 2.4.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [6d58c7e]
|
|
8
|
+
- Updated dependencies [11aa655]
|
|
9
|
+
- Updated dependencies [25d5b15]
|
|
10
|
+
- Updated dependencies [11aa655]
|
|
11
|
+
- Updated dependencies [11aa655]
|
|
12
|
+
- Updated dependencies [25d5b15]
|
|
13
|
+
- Updated dependencies [42cf7a2]
|
|
14
|
+
- Updated dependencies [25d5b15]
|
|
15
|
+
- Updated dependencies [04cb46d]
|
|
16
|
+
- akanjs@2.4.2
|
|
17
|
+
|
|
3
18
|
## 2.4.1
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
|
@@ -55,7 +55,7 @@ interface RootBoundary {
|
|
|
55
55
|
segments: string[];
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
function getRootBoundarySegments(key: string): string[] | null {
|
|
58
|
+
export function getRootBoundarySegments(key: string): string[] | null {
|
|
59
59
|
const match = LAYOUT_KEY_RE.exec(key);
|
|
60
60
|
if (!match) return null;
|
|
61
61
|
const prefix = match[1]?.replace(/\/$/, "");
|
|
@@ -76,7 +76,7 @@ function implicitDictionaryMacroAbsPath(appCwdPath: string): string {
|
|
|
76
76
|
return path.join(path.resolve(appCwdPath), IMPLICIT_DICT_DIR, "useDict.ts");
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
function isRootBoundarySegments(segments: string[], basePaths: Iterable<string>): boolean {
|
|
79
|
+
export function isRootBoundarySegments(segments: string[], basePaths: Iterable<string>): boolean {
|
|
80
80
|
const firstVisibleIndex = segments.findIndex((segment) => !/^\(.+\)$/.test(segment));
|
|
81
81
|
if (firstVisibleIndex === -1) return segments.length <= 1;
|
|
82
82
|
if (segments.slice(firstVisibleIndex + 1).some((segment) => /^\(.+\)$/.test(segment))) return false;
|
package/executors.test.ts
CHANGED
|
@@ -621,6 +621,64 @@ describe("Workspace and app executor environment contracts", () => {
|
|
|
621
621
|
});
|
|
622
622
|
});
|
|
623
623
|
|
|
624
|
+
describe("root layout source validation during page key discovery", () => {
|
|
625
|
+
const makeRouteValidationApp = async (appName: string, config: string, files: Record<string, string>) => {
|
|
626
|
+
const root = await makeTempRoot();
|
|
627
|
+
process.env.AKAN_PUBLIC_REPO_NAME = "repo";
|
|
628
|
+
process.env.AKAN_PUBLIC_SERVE_DOMAIN = "example.com";
|
|
629
|
+
process.env.AKAN_PUBLIC_ENV = "local";
|
|
630
|
+
await writeJson(path.join(root, "package.json"), rootPackageJson());
|
|
631
|
+
await mkdir(path.join(root, "apps", appName), { recursive: true });
|
|
632
|
+
await writeFile(path.join(root, `apps/${appName}/akan.config.ts`), config);
|
|
633
|
+
for (const [file, source] of Object.entries(files)) {
|
|
634
|
+
const filePath = path.join(root, `apps/${appName}/page`, file);
|
|
635
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
636
|
+
await writeFile(filePath, source);
|
|
637
|
+
}
|
|
638
|
+
const workspace = new WorkspaceExecutor({ workspaceRoot: root, repoName: "repo" });
|
|
639
|
+
return AppExecutor.from(workspace, appName);
|
|
640
|
+
};
|
|
641
|
+
const wsConnectLayout = [
|
|
642
|
+
"export const wsConnect = false;",
|
|
643
|
+
"export default function Layout({ children }) { return children; }",
|
|
644
|
+
"",
|
|
645
|
+
].join("\n");
|
|
646
|
+
|
|
647
|
+
test("accepts wsConnect on a configured base-path root layout", async () => {
|
|
648
|
+
process.env.AKAN_PUBLIC_BASE_PATHS = "web,admin";
|
|
649
|
+
const app = await makeRouteValidationApp(
|
|
650
|
+
"base-path-root-ws",
|
|
651
|
+
[
|
|
652
|
+
"export default {",
|
|
653
|
+
' routes: [{ basePath: "web", domains: {} }, { basePath: "admin", domains: {} }],',
|
|
654
|
+
"};",
|
|
655
|
+
"",
|
|
656
|
+
].join("\n"),
|
|
657
|
+
{ "admin/_layout.tsx": wsConnectLayout },
|
|
658
|
+
);
|
|
659
|
+
|
|
660
|
+
await expect(app.getPageKeys({ refresh: true })).resolves.toEqual(["./admin/_layout.tsx"]);
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
test("rejects wsConnect on a nested layout", async () => {
|
|
664
|
+
const app = await makeRouteValidationApp(
|
|
665
|
+
"nested-layout-ws",
|
|
666
|
+
'export default { routes: [{ basePath: "admin", domains: {} }] };\n',
|
|
667
|
+
{ "admin/users/_layout.tsx": wsConnectLayout },
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
await expect(app.getPageKeys({ refresh: true })).rejects.toThrow(/unsupported export "wsConnect"/);
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
test("accepts wsConnect on a grouped root layout", async () => {
|
|
674
|
+
const app = await makeRouteValidationApp("grouped-root-ws", "export default {};\n", {
|
|
675
|
+
"(docs)/_layout.tsx": wsConnectLayout,
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
await expect(app.getPageKeys({ refresh: true })).resolves.toEqual(["./(docs)/_layout.tsx"]);
|
|
679
|
+
});
|
|
680
|
+
});
|
|
681
|
+
|
|
624
682
|
test("accepts metadata route exports during page key discovery", async () => {
|
|
625
683
|
const root = await makeTempRoot();
|
|
626
684
|
process.env.AKAN_PUBLIC_REPO_NAME = "repo";
|
package/executors.ts
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
upsertAgentBlock,
|
|
41
41
|
} from "./agentsIndex";
|
|
42
42
|
import { AkanAppConfig, AkanLibConfig, decreaseBuildNum, increaseBuildNum } from "./akanConfig";
|
|
43
|
+
import { getRootBoundarySegments, isRootBoundarySegments } from "./artifact/implicitRootLayout";
|
|
43
44
|
import { FileSys } from "./fileSys";
|
|
44
45
|
import { getDirname } from "./getDirname";
|
|
45
46
|
import { Linter } from "./linter";
|
|
@@ -1469,7 +1470,8 @@ export class AppExecutor extends SysExecutor {
|
|
|
1469
1470
|
);
|
|
1470
1471
|
}
|
|
1471
1472
|
if (!owner) owners.set(routeId, { absPath, fromLib });
|
|
1472
|
-
const
|
|
1473
|
+
const layoutSegments = getRootBoundarySegments(key);
|
|
1474
|
+
const isRootLayout = layoutSegments !== null && isRootBoundarySegments(layoutSegments, akanConfig.basePaths);
|
|
1473
1475
|
const routeSource = await Bun.file(absPath).text();
|
|
1474
1476
|
const validator = await AppExecutor.#getRouteSourceValidator();
|
|
1475
1477
|
if (parsed.kind === "overrides") validator.validateOverridesSourceExports(routeSource, absPath);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/devkit",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.53",
|
|
4
4
|
"sourceType": "module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@langchain/openai": "^1.4.6",
|
|
46
46
|
"@tailwindcss/node": "^4.3.0",
|
|
47
47
|
"@trapezedev/project": "^7.1.4",
|
|
48
|
-
"akanjs": "3.0.0-alpha.
|
|
48
|
+
"akanjs": "3.0.0-alpha.53",
|
|
49
49
|
"chalk": "^5.6.2",
|
|
50
50
|
"commander": "^14.0.3",
|
|
51
51
|
"dayjs": "^1.11.20",
|