@akanjs/devkit 3.0.0-beta.9 → 3.0.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.
- package/DEV_RUNTIME_KNOBS.md +44 -26
- package/README.ko.md +21 -7
- package/README.md +17 -8
- package/abstractDoc.test.ts +6 -15
- package/abstractDoc.ts +6 -8
- package/agentsIndex.test.ts +4 -7
- package/agentsIndex.ts +6 -22
- package/akanApp/BackendImportGraph.test.ts +8 -22
- package/akanApp/BackendImportGraph.ts +1 -20
- package/akanApp/akanApp.host.test.ts +56 -3
- package/akanApp/akanApp.host.ts +218 -278
- package/akanApp/devBootLatch.test.ts +39 -0
- package/akanApp/devBootLatch.ts +39 -0
- package/akanApp/devHostPolicy.test.ts +81 -35
- package/akanApp/devHostPolicy.ts +41 -102
- package/akanConfig/akanBin.test.ts +62 -0
- package/akanConfig/akanBin.ts +78 -0
- package/akanConfig/akanConfig.test.ts +439 -141
- package/akanConfig/akanConfig.ts +359 -275
- package/akanConfig/index.ts +1 -0
- package/akanConfig/types.ts +22 -8
- package/akanContext.ts +110 -160
- package/akanMcpContract.ts +28 -73
- package/appSelectionMemory.ts +1 -4
- package/applicationBuildReporter.ts +37 -5
- package/applicationBuildRunner.test.ts +41 -5
- package/applicationBuildRunner.ts +71 -63
- package/applicationTestPreload.ts +3 -12
- package/artifact/implicitRootLayout.test.ts +32 -30
- package/artifact/implicitRootLayout.ts +58 -106
- package/artifact/routeSeedIndex.test.ts +7 -6
- package/artifact/routeSeedIndex.ts +11 -44
- package/biome.base.json +35 -2
- package/biomeBase.ts +2 -5
- package/cloud/cloudApi.test.ts +202 -0
- package/cloud/cloudApi.ts +77 -39
- package/cloud/configLock.test.ts +64 -0
- package/cloud/configLock.ts +96 -0
- package/cloud/constants.ts +26 -5
- package/cloud/globalConfig.ts +71 -32
- package/codeAgent/agent/AkanCodeServices.ts +97 -0
- package/codeAgent/agent/AkanContextFiles.ts +94 -0
- package/codeAgent/agent/CodeAgent.ts +551 -0
- package/codeAgent/agent/CodeAgentAsks.ts +66 -0
- package/codeAgent/agent/CodeAgentEventMapper.ts +225 -0
- package/codeAgent/agent/CodeAgentGate.ts +93 -0
- package/codeAgent/agent/CodeAgentProxy.ts +82 -0
- package/codeAgent/agent/CodeAgentRpcHost.ts +103 -0
- package/codeAgent/agent/CodeAgentRpcListener.ts +109 -0
- package/codeAgent/agent/CodeAgentStreamPrinter.ts +86 -0
- package/codeAgent/agent/CodeAgentSuspended.ts +85 -0
- package/codeAgent/agent/CodeAgentUi.ts +47 -0
- package/codeAgent/agent/CodeMailbox.ts +148 -0
- package/codeAgent/agent/CodeSessionFork.ts +56 -0
- package/codeAgent/agent/CodeSessionIndex.ts +78 -0
- package/codeAgent/agent/SubagentPool.ts +214 -0
- package/codeAgent/agent/akanCodeModel.ts +47 -0
- package/codeAgent/agent/akanCodePaths.ts +31 -0
- package/codeAgent/agent/akanContextFiles.test.ts +114 -0
- package/codeAgent/agent/akanSystemPrompt.ts +46 -0
- package/codeAgent/agent/codeAgent.test.ts +178 -0
- package/codeAgent/agent/codeAgentContract.test.ts +523 -0
- package/codeAgent/agent/codeAgentProxy.test.ts +74 -0
- package/codeAgent/agent/codeAgentRpcListener.test.ts +113 -0
- package/codeAgent/agent/codeAgentSuspended.test.ts +47 -0
- package/codeAgent/agent/codeMailbox.test.ts +76 -0
- package/codeAgent/agent/codeSessionFork.test.ts +58 -0
- package/codeAgent/agent/codeSessionIndex.test.ts +77 -0
- package/codeAgent/agent/consoleToStderr.ts +8 -0
- package/codeAgent/agent/jsonLines.ts +29 -0
- package/codeAgent/agent/stringArg.ts +5 -0
- package/codeAgent/feedback/DevLogFeedback.ts +82 -0
- package/codeAgent/feedback/PreviewChrome.ts +82 -0
- package/codeAgent/feedback/PreviewFeedback.ts +46 -0
- package/codeAgent/feedback/PreviewView.ts +95 -0
- package/codeAgent/feedback/TurnFeedback.ts +98 -0
- package/codeAgent/feedback/VerifyFeedback.ts +40 -0
- package/codeAgent/feedback/previewChrome.test.ts +73 -0
- package/codeAgent/index.ts +34 -0
- package/codeAgent/skills/akan-code/SKILL.md +130 -0
- package/codeAgent/skills/akan-debug/SKILL.md +42 -0
- package/codeAgent/skills/akan-deps/SKILL.md +50 -0
- package/codeAgent/skills/akan-err/SKILL.md +39 -0
- package/codeAgent/skills/akan-module/SKILL.md +45 -0
- package/codeAgent/skills/akan-scaffold/SKILL.md +76 -0
- package/codeAgent/skills/akan-scalar/SKILL.md +52 -0
- package/codeAgent/skills/akan-service/SKILL.md +34 -0
- package/codeAgent/skills/akan-store/SKILL.md +67 -0
- package/codeAgent/skills/akan-ui/SKILL.md +63 -0
- package/codeAgent/skills/akan-validate/SKILL.md +44 -0
- package/codeAgent/tools/AkanCli.ts +50 -0
- package/codeAgent/tools/AkanCodePlugins.ts +136 -0
- package/codeAgent/tools/AkanEditScope.ts +48 -0
- package/codeAgent/tools/AkanEnvKeys.ts +50 -0
- package/codeAgent/tools/AkanToolPack.ts +92 -0
- package/codeAgent/tools/AkanVerifier.ts +48 -0
- package/codeAgent/tools/AskToolPack.ts +99 -0
- package/codeAgent/tools/MailToolPack.ts +76 -0
- package/codeAgent/tools/McpClient.ts +187 -0
- package/codeAgent/tools/McpOAuth.ts +233 -0
- package/codeAgent/tools/McpOAuthLoopback.ts +64 -0
- package/codeAgent/tools/McpServerConfig.ts +129 -0
- package/codeAgent/tools/McpSignIn.ts +158 -0
- package/codeAgent/tools/McpTokenStore.ts +81 -0
- package/codeAgent/tools/McpToolPack.ts +199 -0
- package/codeAgent/tools/SessionToolPack.ts +91 -0
- package/codeAgent/tools/WebToolPack.ts +147 -0
- package/codeAgent/tools/akanCodePlugins.test.ts +677 -0
- package/codeAgent/tools/askToolPack.test.ts +116 -0
- package/codeAgent/tools/mcpOAuth.test.ts +612 -0
- package/codeAgent/tools/mcpServerConfig.test.ts +212 -0
- package/codegenLock.test.ts +4 -13
- package/codegenLock.ts +3 -17
- package/commandDecorators/argMeta.ts +1 -5
- package/commandDecorators/camelToKebabCase.ts +1 -0
- package/commandDecorators/command.ts +46 -102
- package/commandDecorators/commandBuilder.ts +30 -61
- package/commandDecorators/commandDecorators.test.ts +2 -10
- package/commandDecorators/dependencyBuilder.ts +10 -1
- package/commandDecorators/helpFormatter.ts +68 -145
- package/commandDecorators/index.ts +0 -2
- package/commandDecorators/targetMeta.ts +9 -7
- package/createTunnel.ts +7 -14
- package/csrE2e/csrE2eHarness.fixture.ts +505 -0
- package/csrE2e/csrFastRefresh.e2e.test.ts +233 -0
- package/csrE2e/csrPageStack.e2e.test.ts +252 -0
- package/csrE2e/csrPatchFirst.e2e.test.ts +87 -0
- package/csrE2e/csrRootLayout.e2e.test.ts +134 -0
- package/csrE2e/devHmrLatency.e2e.test.ts +391 -0
- package/csrE2e/registryVendor.e2e.test.ts +221 -0
- package/csrE2e/ssrRegistry.e2e.test.ts +644 -0
- package/dependencyScanner.test.ts +4 -16
- package/dependencyScanner.ts +31 -80
- package/devkitUtils.test.ts +48 -20
- package/executors.linkFallback.test.ts +103 -0
- package/executors.test.ts +176 -106
- package/executors.ts +212 -498
- package/fileEditor.ts +9 -37
- package/{getDirname.test.ts → fileSys.test.ts} +5 -3
- package/fileSys.ts +22 -9
- package/formSetterScanner.ts +3 -16
- package/frontendBuild/allRoutesBuilder.ts +7 -21
- package/frontendBuild/autoImportSync.test.ts +27 -38
- package/frontendBuild/autoImportSync.ts +31 -65
- package/frontendBuild/buildRouteClient.test.ts +123 -37
- package/frontendBuild/bundleDefine.test.ts +12 -0
- package/frontendBuild/bundleDefine.ts +16 -0
- package/frontendBuild/clientBuildTypes.ts +5 -36
- package/frontendBuild/clientEntriesBundler.ts +9 -40
- package/frontendBuild/clientEntryDiscovery.test.ts +112 -0
- package/frontendBuild/clientEntryDiscovery.ts +122 -110
- package/frontendBuild/csrArtifactBuilder.ts +9 -31
- package/frontendBuild/csrDevArtifactWriter.test.ts +151 -0
- package/frontendBuild/csrDevArtifactWriter.ts +307 -0
- package/frontendBuild/csrDevBundler.test.ts +66 -0
- package/frontendBuild/csrDevBundler.ts +95 -0
- package/frontendBuild/csrDevFactoryCheck.test.ts +33 -0
- package/frontendBuild/csrDevFactoryCheck.ts +39 -0
- package/frontendBuild/csrDevModuleCompiler.test.ts +293 -0
- package/frontendBuild/csrDevModuleCompiler.ts +422 -0
- package/frontendBuild/csrDevPatcher.test.ts +572 -0
- package/frontendBuild/csrDevPatcher.ts +548 -0
- package/frontendBuild/csrDevPaths.ts +145 -0
- package/frontendBuild/csrDevResolver.test.ts +239 -0
- package/frontendBuild/csrDevResolver.ts +363 -0
- package/frontendBuild/csrDevTypes.ts +61 -0
- package/frontendBuild/csrEntryFiles.ts +24 -0
- package/frontendBuild/cssCandidateCache.test.ts +0 -6
- package/frontendBuild/cssCandidateCache.ts +6 -41
- package/frontendBuild/cssCompiler.ts +31 -82
- package/frontendBuild/cssImportResolver.ts +6 -19
- package/frontendBuild/devChangePlanner.ts +7 -10
- package/frontendBuild/devGeneratedIndexSync.test.ts +12 -27
- package/frontendBuild/devGeneratedIndexSync.ts +1 -4
- package/frontendBuild/devRegistryBundler.ts +192 -0
- package/frontendBuild/fontOptimizer.test.ts +6 -14
- package/frontendBuild/fontOptimizer.ts +15 -72
- package/frontendBuild/fontPruner.test.ts +5 -10
- package/frontendBuild/fontPruner.ts +5 -20
- package/frontendBuild/frontendBuild.test.ts +57 -70
- package/frontendBuild/hmrChangeClassifier.ts +2 -2
- package/frontendBuild/hmrWatcher.test.ts +59 -32
- package/frontendBuild/hmrWatcher.ts +31 -74
- package/frontendBuild/index.ts +4 -0
- package/frontendBuild/pagesBundleBuilder.ts +28 -30
- package/frontendBuild/pagesEntrySourceGenerator.ts +56 -6
- package/frontendBuild/precompressArtifacts.ts +5 -18
- package/frontendBuild/registryMetadataFingerprint.test.ts +63 -0
- package/frontendBuild/registryMetadataFingerprint.ts +28 -0
- package/frontendBuild/routeClientBuilder.ts +100 -62
- package/frontendBuild/routesManifestArtifactSerializer.ts +5 -36
- package/frontendBuild/serverGraphFile.test.ts +77 -0
- package/frontendBuild/serverGraphFile.ts +93 -0
- package/frontendBuild/sourceMtimeIndex.test.ts +41 -97
- package/frontendBuild/sourceMtimeIndex.ts +19 -130
- package/frontendBuild/ssrBaseArtifactBuilder.ts +19 -13
- package/frontendBuild/ssrDevBundler.ts +85 -0
- package/frontendBuild/styleContract.ts +1 -8
- package/frontendBuild/themeValidator.ts +4 -26
- package/frontendBuild/watchRootResolver.test.ts +23 -42
- package/frontendBuild/watchRootResolver.ts +5 -27
- package/getRelatedCnsts.ts +12 -92
- package/incrementalBuilder/buildBatch.proc.ts +147 -63
- package/incrementalBuilder/buildBatchProtocol.ts +13 -38
- package/incrementalBuilder/buildBatchRunner.test.ts +65 -0
- package/incrementalBuilder/buildBatchRunner.ts +26 -38
- package/incrementalBuilder/builderChannel.test.ts +24 -49
- package/incrementalBuilder/builderChannel.ts +6 -37
- package/incrementalBuilder/builderRequestRouter.test.ts +0 -8
- package/incrementalBuilder/builderRequestRouter.ts +5 -24
- package/incrementalBuilder/builderWorkQueue.test.ts +94 -0
- package/incrementalBuilder/builderWorkQueue.ts +126 -0
- package/incrementalBuilder/devWatchBatch.test.ts +21 -24
- package/incrementalBuilder/incrementalBuilder.host.test.ts +53 -56
- package/incrementalBuilder/incrementalBuilder.host.ts +68 -81
- package/incrementalBuilder/incrementalBuilder.proc.test.ts +270 -0
- package/incrementalBuilder/incrementalBuilder.proc.ts +596 -208
- package/index.ts +5 -19
- package/integration/devResourceProbe.ts +50 -56
- package/integration/devStability.integration.test.ts +105 -199
- package/integration/devStabilityHarness.test.ts +13 -28
- package/integration/devStabilityHarness.ts +65 -330
- package/integration/ssrMemoryProbe.ts +41 -167
- package/libSource.test.ts +4 -15
- package/libSource.ts +19 -31
- package/lint/__fixtures__/no-document-cookie/bad.tsx +4 -0
- package/lint/__fixtures__/no-document-cookie/good.tsx +7 -0
- package/lint/__fixtures__/no-web-only-api-outside-webkit/bad.tsx +7 -0
- package/lint/__fixtures__/no-web-only-api-outside-webkit/good.tsx +11 -0
- package/lint/__fixtures__/no-web-storage/bad.tsx +6 -0
- package/lint/__fixtures__/no-web-storage/good.tsx +7 -0
- package/lint/gritRules.test.ts +8 -24
- package/lint/no-deep-internal-import.grit +2 -2
- package/lint/no-document-cookie.grit +29 -0
- package/lint/no-redeclare-predefined-endpoint.grit +2 -1
- package/lint/no-web-only-api-outside-webkit.grit +44 -0
- package/lint/no-web-storage.grit +30 -0
- package/linter.test.ts +1 -2
- package/linter.ts +26 -116
- package/mobile/desktopBin.test.ts +182 -0
- package/mobile/desktopBin.ts +144 -0
- package/mobile/desktopServerStage.test.ts +252 -0
- package/mobile/desktopServerStage.ts +178 -0
- package/mobile/index.ts +9 -0
- package/mobile/mobileTarget.test.ts +57 -8
- package/mobile/mobileTarget.ts +45 -26
- package/mobile/nativeApi.test.ts +30 -0
- package/mobile/nativeApi.ts +40 -0
- package/mobile/nativeApp.test.ts +184 -0
- package/mobile/nativeApp.ts +454 -0
- package/mobile/nativeAppLine.test.ts +69 -0
- package/mobile/nativeAppLine.ts +71 -0
- package/mobile/nativeConfig.test.ts +438 -0
- package/mobile/nativeConfig.ts +294 -0
- package/mobile/nativePluginFolders.test.ts +81 -0
- package/mobile/nativePluginFolders.ts +60 -0
- package/mobile/nativeWebDir.test.ts +80 -0
- package/mobile/nativeWebDir.ts +66 -0
- package/mobile/placeholderAppId.test.ts +13 -0
- package/mobile/placeholderAppId.ts +16 -0
- package/mobile/usageDescriptions.test.ts +27 -0
- package/mobile/usageDescriptions.ts +24 -0
- package/package.json +11 -11
- package/packageExports.test.ts +3 -18
- package/packageExportsMap.ts +3 -19
- package/piDependencyPins.test.ts +46 -0
- package/platformTest/BunTestReport.test.ts +60 -0
- package/platformTest/BunTestReport.ts +65 -0
- package/platformTest/IdleWatchedProcess.test.ts +56 -0
- package/platformTest/IdleWatchedProcess.ts +73 -0
- package/platformTest/LinuxDockerTarget.ts +105 -0
- package/platformTest/PlatformTestRun.test.ts +64 -0
- package/platformTest/PlatformTestRun.ts +141 -0
- package/platformTest/PlatformTestTarget.ts +142 -0
- package/platformTest/TestSnapshot.test.ts +72 -0
- package/platformTest/TestSnapshot.ts +103 -0
- package/platformTest/WindowsSshTarget.ts +151 -0
- package/prompter.ts +3 -13
- package/qualityScanner.test.ts +9 -26
- package/qualityScanner.ts +200 -286
- package/recipeScanner.test.ts +7 -12
- package/recipeScanner.ts +9 -38
- package/repoIdentity.ts +2 -9
- package/routeSourceValidator.test.ts +0 -1
- package/routeSourceValidator.ts +7 -42
- package/scanInfo.ts +91 -225
- package/selectModel.ts +1 -2
- package/semver.ts +3 -5
- package/slicePlanner.test.ts +6 -24
- package/slicePlanner.ts +11 -32
- package/spinner.test.ts +3 -8
- package/spinner.ts +4 -16
- package/sshTunnel.ts +1 -6
- package/ssrScanner.test.ts +1 -6
- package/ssrScanner.ts +103 -113
- package/stripAnsi.ts +3 -0
- package/subspace.test.ts +9 -25
- package/subspace.ts +48 -115
- package/subspaceConfig.ts +3 -11
- package/testHelpers.ts +194 -0
- package/transforms/asyncDefaultExportDetector.ts +3 -11
- package/transforms/barrelAnalyzer.ts +43 -135
- package/transforms/barrelImportsPlugin.ts +38 -175
- package/transforms/externalizeFrameworkPlugin.test.ts +39 -118
- package/transforms/externalizeFrameworkPlugin.ts +13 -87
- package/transforms/moduleSyntax.ts +32 -0
- package/transforms/rscUseClientTransform.ts +42 -20
- package/transforms/serverEnvPlugin.test.ts +103 -0
- package/transforms/serverEnvPlugin.ts +41 -0
- package/transforms/transforms.test.ts +166 -44
- package/transforms/tsconfigPackageResolver.test.ts +6 -24
- package/transforms/useClientBundlePlugin.ts +6 -23
- package/typeChecker.ts +7 -63
- package/types.ts +2 -0
- package/uploadRelease.ts +10 -25
- package/workflow/artifacts.ts +18 -0
- package/workflow/executor.test.ts +1 -12
- package/workflow/executor.ts +101 -110
- package/workflow/index.ts +0 -1
- package/workflow/moduleIndex.test.ts +4 -15
- package/workflow/moduleIndex.ts +9 -49
- package/workflow/plan.ts +18 -25
- package/workflow/render.ts +80 -96
- package/workflow/rolloutGate.test.ts +1 -1
- package/workflow/source.ts +52 -69
- package/workflow/sourceAst.ts +50 -0
- package/workspaceLayout.test.ts +18 -3
- package/workspaceLayout.ts +22 -23
- package/abstractCompactor.ts +0 -112
- package/aiEditor.test.ts +0 -60
- package/aiEditor.ts +0 -387
- package/applicationReleasePackager.ts +0 -209
- package/capacitorApp.test.ts +0 -372
- package/capacitorApp.ts +0 -1648
- package/commandDecorators/commandMeta.ts +0 -7
- package/commandDecorators/types.ts +0 -10
- package/getDirname.ts +0 -4
- package/guideline.ts +0 -19
- package/local/optimize-resource/ipcprobe/child.ts +0 -1
- package/local/optimize-resource/ipcprobe/parent.ts +0 -11
- package/workflow/primitive.ts +0 -59
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readdir, rm } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import type { App } from "../commandDecorators";
|
|
4
4
|
import { AsyncDefaultExportDetector } from "../transforms/asyncDefaultExportDetector";
|
|
@@ -11,23 +11,17 @@ export interface PageEntry {
|
|
|
11
11
|
|
|
12
12
|
const LAYOUT_KEY_RE = /^\.\/(.+\/)?_layout\.(tsx|ts|jsx|js)$/;
|
|
13
13
|
|
|
14
|
-
async function appHasStModule(appCwdPath: string): Promise<boolean> {
|
|
15
|
-
return Bun.file(path.join(appCwdPath, "lib", "st.ts")).exists();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
const IMPLICIT_LAYOUT_DIR = path.join(".akan", "generated", "root-layouts");
|
|
19
15
|
const IMPLICIT_DICT_DIR = path.join(".akan", "generated", "dict");
|
|
20
16
|
const IMPLICIT_OVERRIDES_DIR = path.join(".akan", "generated", "overrides");
|
|
21
17
|
const OVERRIDES_KEY_RE = /^\.\/(.+\/)?_overrides\.(tsx|ts|jsx|js)$/;
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* resolve it — and the author never writes `"use client"`.
|
|
30
|
-
*/
|
|
19
|
+
const importSpecifier = (fromAbsPath: string, toAbsPath: string) => {
|
|
20
|
+
const rel = path.relative(path.dirname(fromAbsPath), toAbsPath).split(path.sep).join("/");
|
|
21
|
+
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// UiOverrideProvider is a client component, so `_overrides.tsx` mounts through a generated "use client" layout.
|
|
31
25
|
async function writeGeneratedOverridesLayoutFile(opts: {
|
|
32
26
|
appCwdPath: string;
|
|
33
27
|
key: string;
|
|
@@ -35,12 +29,10 @@ async function writeGeneratedOverridesLayoutFile(opts: {
|
|
|
35
29
|
}): Promise<string> {
|
|
36
30
|
const filename = `${opts.key.replace(/^\.\//, "").replace(/[^a-zA-Z0-9]+/g, "_")}.tsx`;
|
|
37
31
|
const absPath = path.join(path.resolve(opts.appCwdPath), IMPLICIT_OVERRIDES_DIR, filename);
|
|
38
|
-
const userRel = path.relative(path.dirname(absPath), opts.userAbsPath).split(path.sep).join("/");
|
|
39
|
-
const userSpecifier = userRel.startsWith(".") ? userRel : `./${userRel}`;
|
|
40
32
|
const source = `"use client";
|
|
41
33
|
import { UiOverrideProvider } from "akanjs/ui";
|
|
42
34
|
import { createElement, type ReactNode } from "react";
|
|
43
|
-
import value from ${JSON.stringify(
|
|
35
|
+
import value from ${JSON.stringify(importSpecifier(absPath, opts.userAbsPath))};
|
|
44
36
|
|
|
45
37
|
export default function AkanUiOverridesLayout({ children }: { children?: ReactNode }) {
|
|
46
38
|
return createElement(UiOverrideProvider, { value }, children);
|
|
@@ -50,6 +42,17 @@ export default function AkanUiOverridesLayout({ children }: { children?: ReactNo
|
|
|
50
42
|
return absPath;
|
|
51
43
|
}
|
|
52
44
|
|
|
45
|
+
async function pruneGeneratedFiles(dirAbsPath: string, keepAbsPaths: string[]): Promise<void> {
|
|
46
|
+
const keep = new Set(keepAbsPaths);
|
|
47
|
+
const names = await readdir(dirAbsPath).catch(() => [] as string[]);
|
|
48
|
+
await Promise.all(
|
|
49
|
+
names
|
|
50
|
+
.map((name) => path.join(dirAbsPath, name))
|
|
51
|
+
.filter((absPath) => !keep.has(absPath))
|
|
52
|
+
.map((absPath) => rm(absPath, { force: true })),
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
53
56
|
interface RootBoundary {
|
|
54
57
|
sourceKey: string | null;
|
|
55
58
|
sourceAbsPath: string | null;
|
|
@@ -73,10 +76,6 @@ function implicitRootLayoutAbsPath(appCwdPath: string, segments: string[]): stri
|
|
|
73
76
|
return path.join(path.resolve(appCwdPath), IMPLICIT_LAYOUT_DIR, filename);
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
function implicitDictionaryMacroAbsPath(appCwdPath: string): string {
|
|
77
|
-
return path.join(path.resolve(appCwdPath), IMPLICIT_DICT_DIR, "useDict.ts");
|
|
78
|
-
}
|
|
79
|
-
|
|
80
79
|
export function isRootBoundarySegments(segments: string[], basePaths: Iterable<string>): boolean {
|
|
81
80
|
const firstVisibleIndex = segments.findIndex((segment) => !/^\(.+\)$/.test(segment));
|
|
82
81
|
if (firstVisibleIndex === -1) return segments.length <= 1;
|
|
@@ -99,10 +98,7 @@ function findRootBoundaries(pageKeys: string[], appCwdPath: string, basePaths: I
|
|
|
99
98
|
segments,
|
|
100
99
|
});
|
|
101
100
|
}
|
|
102
|
-
|
|
103
|
-
if (!hasExplicitRootBoundary && boundaries.size === 0) {
|
|
104
|
-
boundaries.set("", { sourceKey: null, sourceAbsPath: null, segments: [] });
|
|
105
|
-
}
|
|
101
|
+
if (boundaries.size === 0) boundaries.set("", { sourceKey: null, sourceAbsPath: null, segments: [] });
|
|
106
102
|
return [...boundaries.values()].sort((a, b) => a.segments.join("/").localeCompare(b.segments.join("/")));
|
|
107
103
|
}
|
|
108
104
|
|
|
@@ -123,11 +119,6 @@ function findExplicitRootLayoutAbsPath(pageKeys: string[], appCwdPath: string):
|
|
|
123
119
|
return rootLayoutKey ? path.resolve(appCwdPath, "page", rootLayoutKey.replace(/^\.\//, "")) : null;
|
|
124
120
|
}
|
|
125
121
|
|
|
126
|
-
function routePrefixForSegments(segments: string[]): string | null {
|
|
127
|
-
const visible = segments.filter((segment) => !/^\(.+\)$/.test(segment));
|
|
128
|
-
return visible[0] ?? null;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
122
|
async function assertEnvClientConvention(appCwdPath: string, appName: string) {
|
|
132
123
|
const envPath = path.join(appCwdPath, "env", "env.client.ts");
|
|
133
124
|
if (!(await Bun.file(envPath).exists())) {
|
|
@@ -138,8 +129,7 @@ async function assertEnvClientConvention(appCwdPath: string, appName: string) {
|
|
|
138
129
|
}
|
|
139
130
|
|
|
140
131
|
async function writeGeneratedDictionaryMacroFile(appCwdPath: string, appName: string): Promise<string> {
|
|
141
|
-
const absPath =
|
|
142
|
-
await mkdir(path.dirname(absPath), { recursive: true });
|
|
132
|
+
const absPath = path.join(path.resolve(appCwdPath), IMPLICIT_DICT_DIR, "useDict.ts");
|
|
143
133
|
await Bun.write(
|
|
144
134
|
absPath,
|
|
145
135
|
`import { getAllDictionary } from "@apps/${appName}/lib/dict" with { type: "macro" };
|
|
@@ -163,35 +153,20 @@ async function writeGeneratedRootLayoutFile(opts: {
|
|
|
163
153
|
? await writeGeneratedDictionaryMacroFile(opts.appCwdPath, opts.appName)
|
|
164
154
|
: null;
|
|
165
155
|
const absPath = implicitRootLayoutAbsPath(opts.appCwdPath, opts.boundary.segments);
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
? path.relative(path.dirname(absPath), dictMacroAbsPath).split(path.sep).join("/")
|
|
169
|
-
: null;
|
|
170
|
-
const dictMacroSpecifier = dictMacroRel ? (dictMacroRel.startsWith(".") ? dictMacroRel : `./${dictMacroRel}`) : null;
|
|
171
|
-
const sourceRel = opts.boundary.sourceAbsPath
|
|
172
|
-
? path.relative(path.dirname(absPath), opts.boundary.sourceAbsPath).split(path.sep).join("/")
|
|
173
|
-
: null;
|
|
174
|
-
const sourceSpecifier = sourceRel ? (sourceRel.startsWith(".") ? sourceRel : `./${sourceRel}`) : null;
|
|
156
|
+
const dictMacroSpecifier = dictMacroAbsPath ? importSpecifier(absPath, dictMacroAbsPath) : null;
|
|
157
|
+
const sourceSpecifier = opts.boundary.sourceAbsPath ? importSpecifier(absPath, opts.boundary.sourceAbsPath) : null;
|
|
175
158
|
const inheritedSourceAbsPath =
|
|
176
159
|
opts.rootSourceAbsPath && opts.rootSourceAbsPath !== opts.boundary.sourceAbsPath ? opts.rootSourceAbsPath : null;
|
|
177
|
-
const
|
|
178
|
-
? path.relative(path.dirname(absPath), inheritedSourceAbsPath).split(path.sep).join("/")
|
|
179
|
-
: null;
|
|
180
|
-
const inheritedSourceSpecifier = inheritedSourceRel
|
|
181
|
-
? inheritedSourceRel.startsWith(".")
|
|
182
|
-
? inheritedSourceRel
|
|
183
|
-
: `./${inheritedSourceRel}`
|
|
184
|
-
: null;
|
|
160
|
+
const inheritedSourceSpecifier = inheritedSourceAbsPath ? importSpecifier(absPath, inheritedSourceAbsPath) : null;
|
|
185
161
|
const clientImport = opts.includeStInit
|
|
186
162
|
? `import { st } from "@apps/${opts.appName}/client";\nvoid st;\n`
|
|
187
163
|
: `import "@apps/${opts.appName}/client";\n`;
|
|
188
|
-
|
|
189
|
-
// the same afterwards, and this file never has to know which shape the app wrote.
|
|
164
|
+
//? resolveRouteModule reads a rootLayout() chain and the legacy named exports alike.
|
|
190
165
|
const inheritedLabel = inheritedSourceAbsPath ? path.relative(opts.appCwdPath, inheritedSourceAbsPath) : "";
|
|
191
166
|
const inheritedImport = inheritedSourceSpecifier
|
|
192
167
|
? `import * as inheritedModule from ${JSON.stringify(inheritedSourceSpecifier)};\nconst inheritedLayout = resolveRouteModule(inheritedModule as never, ${JSON.stringify(inheritedLabel)}).module as LayoutModule;\n`
|
|
193
168
|
: "const inheritedLayout: LayoutModule = {};\n";
|
|
194
|
-
const prefix =
|
|
169
|
+
const prefix = opts.boundary.segments.find((segment) => !/^\(.+\)$/.test(segment)) ?? null;
|
|
195
170
|
const userLabel = opts.boundary.sourceAbsPath ? path.relative(opts.appCwdPath, opts.boundary.sourceAbsPath) : "";
|
|
196
171
|
const userImport = sourceSpecifier
|
|
197
172
|
? `import * as userModule from ${JSON.stringify(sourceSpecifier)};\nconst userLayout = resolveRouteModule(userModule as never, ${JSON.stringify(userLabel)}).module as LayoutModule;\nconst UserLayout = userLayout.default as (props: LayoutProps) => ReactNode | Promise<ReactNode>;\n`
|
|
@@ -200,9 +175,8 @@ async function writeGeneratedRootLayoutFile(opts: {
|
|
|
200
175
|
? await AsyncDefaultExportDetector.detect(opts.boundary.sourceAbsPath)
|
|
201
176
|
: false;
|
|
202
177
|
const userLayoutElement = "<UserLayout params={params} searchParams={searchParams}>{children}</UserLayout>";
|
|
203
|
-
// React has no async client component, so
|
|
204
|
-
//
|
|
205
|
-
// the layout's own awaits instead of streaming it as its own Flight chunk.
|
|
178
|
+
// React has no async client component, so CSR awaits an async layout's node; RSC keeps the element, since
|
|
179
|
+
// awaiting there would hold the shell behind the layout's own awaits instead of streaming it.
|
|
206
180
|
const layoutSignature = isAsyncUserLayout
|
|
207
181
|
? "export default async function GeneratedLayout"
|
|
208
182
|
: "export default function GeneratedLayout";
|
|
@@ -215,6 +189,19 @@ async function writeGeneratedRootLayoutFile(opts: {
|
|
|
215
189
|
: "";
|
|
216
190
|
const layoutChild = isAsyncUserLayout ? "{layout}" : userLayoutElement;
|
|
217
191
|
const layoutReturn = isAsyncUserLayout ? "layout" : userLayoutElement;
|
|
192
|
+
const layoutExports = `export async function generateHead(props: PageProps) {
|
|
193
|
+
if (userLayout.generateHead) return userLayout.generateHead(props);
|
|
194
|
+
if (userLayout.head !== undefined) return userLayout.head;
|
|
195
|
+
if (inheritedLayout.generateHead) return inheritedLayout.generateHead(props);
|
|
196
|
+
return inheritedLayout.head;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export const NotFound = userLayout.NotFound ?? inheritedLayout.NotFound;
|
|
200
|
+
export const Error = userLayout.Error ?? inheritedLayout.Error;
|
|
201
|
+
export const pageConfig = userLayout.pageConfig ?? inheritedLayout.pageConfig;
|
|
202
|
+
|
|
203
|
+
${layoutSignature}({ children, params, searchParams }: LayoutProps) {
|
|
204
|
+
${layoutBinding} return `;
|
|
218
205
|
const source = opts.includeSystemProvider
|
|
219
206
|
? `import type { LayoutModule, LayoutProps, PageProps } from "akanjs/client";
|
|
220
207
|
import { loadFonts, resolveRouteModule } from "akanjs/client";
|
|
@@ -229,26 +216,7 @@ if (defaultFonts.length > 1) throw new Error("[route-convention] only one defaul
|
|
|
229
216
|
const defaultFont = defaultFonts[0];
|
|
230
217
|
const defaultFontClassName = defaultFont ? (defaultFont.className ?? \`font-\${defaultFont.name}\`) : undefined;
|
|
231
218
|
|
|
232
|
-
|
|
233
|
-
if (userLayout.generateHead) return userLayout.generateHead(props);
|
|
234
|
-
if (userLayout.head !== undefined) return userLayout.head;
|
|
235
|
-
if (inheritedLayout.generateHead) return inheritedLayout.generateHead(props);
|
|
236
|
-
return inheritedLayout.head;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export async function generateMetadata(props: PageProps) {
|
|
240
|
-
if (userLayout.generateMetadata) return userLayout.generateMetadata(props);
|
|
241
|
-
if (userLayout.metadata !== undefined) return userLayout.metadata;
|
|
242
|
-
if (inheritedLayout.generateMetadata) return inheritedLayout.generateMetadata(props);
|
|
243
|
-
return inheritedLayout.metadata;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
export const NotFound = userLayout.NotFound ?? inheritedLayout.NotFound;
|
|
247
|
-
export const Error = userLayout.Error ?? inheritedLayout.Error;
|
|
248
|
-
export const pageConfig = userLayout.pageConfig ?? inheritedLayout.pageConfig;
|
|
249
|
-
|
|
250
|
-
${layoutSignature}({ children, params, searchParams }: LayoutProps) {
|
|
251
|
-
${layoutBinding} return (
|
|
219
|
+
${layoutExports}(
|
|
252
220
|
<System.Provider
|
|
253
221
|
of={GeneratedLayout as never}
|
|
254
222
|
appName=${JSON.stringify(opts.appName)}
|
|
@@ -258,7 +226,6 @@ ${layoutBinding} return (
|
|
|
258
226
|
theme={userLayout.theme ?? inheritedLayout.theme}
|
|
259
227
|
fonts={loadFonts(userFonts)}
|
|
260
228
|
className={defaultFontClassName}
|
|
261
|
-
gaTrackingId={userLayout.gaTrackingId ?? inheritedLayout.gaTrackingId}
|
|
262
229
|
layoutStyle={userLayout.layoutStyle ?? inheritedLayout.layoutStyle}
|
|
263
230
|
reconnect={userLayout.reconnect ?? inheritedLayout.reconnect ?? false}
|
|
264
231
|
wsConnect={userLayout.wsConnect ?? inheritedLayout.wsConnect ?? true}
|
|
@@ -273,36 +240,13 @@ ${layoutBinding} return (
|
|
|
273
240
|
import { resolveRouteModule } from "akanjs/client";
|
|
274
241
|
import type { ReactNode } from "react";
|
|
275
242
|
${inheritedImport}${userImport}
|
|
276
|
-
|
|
277
|
-
if (userLayout.generateHead) return userLayout.generateHead(props);
|
|
278
|
-
if (userLayout.head !== undefined) return userLayout.head;
|
|
279
|
-
if (inheritedLayout.generateHead) return inheritedLayout.generateHead(props);
|
|
280
|
-
return inheritedLayout.head;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
export async function generateMetadata(props: PageProps) {
|
|
284
|
-
if (userLayout.generateMetadata) return userLayout.generateMetadata(props);
|
|
285
|
-
if (userLayout.metadata !== undefined) return userLayout.metadata;
|
|
286
|
-
if (inheritedLayout.generateMetadata) return inheritedLayout.generateMetadata(props);
|
|
287
|
-
return inheritedLayout.metadata;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
export const NotFound = userLayout.NotFound ?? inheritedLayout.NotFound;
|
|
291
|
-
export const Error = userLayout.Error ?? inheritedLayout.Error;
|
|
292
|
-
export const pageConfig = userLayout.pageConfig ?? inheritedLayout.pageConfig;
|
|
293
|
-
|
|
294
|
-
${layoutSignature}({ children, params, searchParams }: LayoutProps) {
|
|
295
|
-
${layoutBinding} return ${layoutReturn};
|
|
243
|
+
${layoutExports}${layoutReturn};
|
|
296
244
|
}
|
|
297
245
|
`;
|
|
298
246
|
await Bun.write(absPath, source);
|
|
299
247
|
return absPath;
|
|
300
248
|
}
|
|
301
249
|
|
|
302
|
-
/**
|
|
303
|
-
* When no root `page/_layout.*` exists on disk, merge a generated implicit root layout
|
|
304
|
-
* (with generated client runtime registration and optional `void st` when `lib/st.ts` exists).
|
|
305
|
-
*/
|
|
306
250
|
export async function resolveSsrPageEntries(opts: {
|
|
307
251
|
appCwdPath: string;
|
|
308
252
|
appName: string;
|
|
@@ -310,7 +254,7 @@ export async function resolveSsrPageEntries(opts: {
|
|
|
310
254
|
basePaths?: Iterable<string>;
|
|
311
255
|
}): Promise<PageEntry[]> {
|
|
312
256
|
const absPageDir = path.resolve(opts.appCwdPath, "page");
|
|
313
|
-
const hasSt = await
|
|
257
|
+
const hasSt = await Bun.file(path.join(opts.appCwdPath, "lib", "st.ts")).exists();
|
|
314
258
|
const basePaths = opts.basePaths ?? [];
|
|
315
259
|
const rootSourceAbsPath = findExplicitRootLayoutAbsPath(opts.pageKeys, opts.appCwdPath);
|
|
316
260
|
const rootBoundaries = findRootBoundaries(opts.pageKeys, opts.appCwdPath, basePaths);
|
|
@@ -325,9 +269,7 @@ export async function resolveSsrPageEntries(opts: {
|
|
|
325
269
|
.filter((key) => !rootLayoutKeys.has(key))
|
|
326
270
|
.map(async (key) => {
|
|
327
271
|
const userAbsPath = path.resolve(absPageDir, key);
|
|
328
|
-
|
|
329
|
-
// so the author writes no directive; the raw manifest becomes a build seed so its slot components (and
|
|
330
|
-
// the manifest itself) enter the client graph / RSC client manifest.
|
|
272
|
+
//? The raw manifest is a seed, so it and its slot components enter the client graph and RSC client manifest.
|
|
331
273
|
if (OVERRIDES_KEY_RE.test(key)) {
|
|
332
274
|
const moduleAbsPath = await writeGeneratedOverridesLayoutFile({
|
|
333
275
|
appCwdPath: opts.appCwdPath,
|
|
@@ -353,9 +295,19 @@ export async function resolveSsrPageEntries(opts: {
|
|
|
353
295
|
seedAbsPaths: [...new Set([boundary.sourceAbsPath, rootSourceAbsPath].filter((absPath) => absPath !== null))],
|
|
354
296
|
})),
|
|
355
297
|
);
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
298
|
+
//? A moved `_overrides.tsx` or root layout leaves a wrapper importing a file that is gone.
|
|
299
|
+
const appCwdAbsPath = path.resolve(opts.appCwdPath);
|
|
300
|
+
await Promise.all([
|
|
301
|
+
pruneGeneratedFiles(
|
|
302
|
+
path.join(appCwdAbsPath, IMPLICIT_OVERRIDES_DIR),
|
|
303
|
+
base.filter(({ key }) => OVERRIDES_KEY_RE.test(key)).map(({ moduleAbsPath }) => moduleAbsPath),
|
|
304
|
+
),
|
|
305
|
+
pruneGeneratedFiles(
|
|
306
|
+
path.join(appCwdAbsPath, IMPLICIT_LAYOUT_DIR),
|
|
307
|
+
generated.map(({ moduleAbsPath }) => moduleAbsPath),
|
|
308
|
+
),
|
|
309
|
+
]);
|
|
310
|
+
return [...base, ...generated].sort((a, b) => a.key.localeCompare(b.key));
|
|
359
311
|
}
|
|
360
312
|
|
|
361
313
|
export async function resolveSsrPageEntriesForApp(app: App, pageKeys: string[]): Promise<PageEntry[]> {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import path from "node:path";
|
|
2
3
|
import { computeRouteSeedIndex, serializeRouteSeedIndexForArtifact } from "./routeSeedIndex";
|
|
3
4
|
|
|
4
5
|
describe("computeRouteSeedIndex", () => {
|
|
@@ -19,10 +20,10 @@ describe("computeRouteSeedIndex", () => {
|
|
|
19
20
|
]);
|
|
20
21
|
|
|
21
22
|
const leaf = index.entries.find((entry) => entry.routeId === "/:lang/foo");
|
|
22
|
-
expect(leaf?.seeds).toContain("/app/page/foo.tsx");
|
|
23
|
-
expect(leaf?.seeds).not.toContain("/app/page/foo/_layout.tsx");
|
|
24
|
-
expect(leaf?.seeds).toContain("/app/.akan/generated/root-layouts/__root_layout.tsx");
|
|
25
|
-
expect(leaf?.seeds).toContain("/app/page/_layout.tsx");
|
|
23
|
+
expect(leaf?.seeds).toContain(path.resolve("/app/page/foo.tsx"));
|
|
24
|
+
expect(leaf?.seeds).not.toContain(path.resolve("/app/page/foo/_layout.tsx"));
|
|
25
|
+
expect(leaf?.seeds).toContain(path.resolve("/app/.akan/generated/root-layouts/__root_layout.tsx"));
|
|
26
|
+
expect(leaf?.seeds).toContain(path.resolve("/app/page/_layout.tsx"));
|
|
26
27
|
|
|
27
28
|
expect(() =>
|
|
28
29
|
computeRouteSeedIndex([
|
|
@@ -42,8 +43,8 @@ describe("computeRouteSeedIndex", () => {
|
|
|
42
43
|
{ key: "./robots.txt.tsx", moduleAbsPath: "/app/page/robots.txt.tsx" },
|
|
43
44
|
]);
|
|
44
45
|
const robots = index.entries.find((entry) => entry.routeId === "/robots.txt");
|
|
45
|
-
expect(robots?.seeds).not.toContain("/app/.akan/generated/root-layouts/__root_layout.tsx");
|
|
46
|
-
expect(robots?.seeds).not.toContain("/app/page/_layout.tsx");
|
|
46
|
+
expect(robots?.seeds).not.toContain(path.resolve("/app/.akan/generated/root-layouts/__root_layout.tsx"));
|
|
47
|
+
expect(robots?.seeds).not.toContain(path.resolve("/app/page/_layout.tsx"));
|
|
47
48
|
});
|
|
48
49
|
|
|
49
50
|
test("serializes seed paths relative to the artifact directory", () => {
|
|
@@ -1,29 +1,13 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { assertUniqueRoutePatterns, compareRouteSpecificity, parseRouteModuleKey } from "akanjs/common";
|
|
3
|
+
import {
|
|
4
|
+
ROUTE_SEED_INDEX_JSON,
|
|
5
|
+
type RouteSeedEntry,
|
|
6
|
+
type RouteSeedIndex,
|
|
7
|
+
} from "akanjs/server/artifact/routeSeedIndexStore";
|
|
3
8
|
import type { PageEntry } from "./implicitRootLayout";
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
* Build-time utilities for the route seed index. `computeRouteSeedIndex`
|
|
7
|
-
* takes resolved `PageEntry` rows (`key` plus absolute module path — files
|
|
8
|
-
* under `app/` or the generated implicit root layout) and produces — for every
|
|
9
|
-
* route — the list of source files that seed the `"use client"` graph walk.
|
|
10
|
-
*
|
|
11
|
-
* The result is serialized to `route-seed-index.json` by
|
|
12
|
-
* `saveRouteSeedIndex` so the runtime server can call
|
|
13
|
-
* `loadRouteSeedIndex` to restore it without re-importing `pages.ts`
|
|
14
|
-
* (which no longer exists) or reparsing loader sources.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
export interface RouteSeedEntry {
|
|
18
|
-
routeId: string;
|
|
19
|
-
pattern: string;
|
|
20
|
-
seeds: string[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface RouteSeedIndex {
|
|
24
|
-
entries: RouteSeedEntry[];
|
|
25
|
-
globalLayoutFiles: string[];
|
|
26
|
-
}
|
|
10
|
+
export { ROUTE_SEED_INDEX_JSON, type RouteSeedEntry, type RouteSeedIndex };
|
|
27
11
|
|
|
28
12
|
export type SerializedRouteSeedEntry = Pick<RouteSeedEntry, "routeId"> &
|
|
29
13
|
Partial<Pick<RouteSeedEntry, "pattern" | "seeds">>;
|
|
@@ -33,10 +17,6 @@ export interface SerializedRouteSeedIndex {
|
|
|
33
17
|
globalLayoutFiles?: string[];
|
|
34
18
|
}
|
|
35
19
|
|
|
36
|
-
/**
|
|
37
|
-
* Compute the route seed index from `PageEntry`s (disk paths or generated
|
|
38
|
-
* implicit root layout absolute paths).
|
|
39
|
-
*/
|
|
40
20
|
export function computeRouteSeedIndex(pageEntries: PageEntry[]): RouteSeedIndex {
|
|
41
21
|
const layoutsByPrefix = new Map<string, string[]>();
|
|
42
22
|
const pagesBySegments: Array<{
|
|
@@ -51,11 +31,8 @@ export function computeRouteSeedIndex(pageEntries: PageEntry[]): RouteSeedIndex
|
|
|
51
31
|
const parsed = parseRouteModuleKey(key);
|
|
52
32
|
const files = [path.resolve(moduleAbsPath), ...(seedAbsPaths ?? []).map((seed) => path.resolve(seed))];
|
|
53
33
|
if (parsed.kind === "layout" || parsed.kind === "overrides") {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const prefix = parsed.routeSegments.join("/");
|
|
57
|
-
const prev = layoutsByPrefix.get(prefix) ?? [];
|
|
58
|
-
layoutsByPrefix.set(prefix, [...prev, ...files]);
|
|
34
|
+
//? Every route under an overrides prefix needs its "use client" wrapper in the client graph, as with a layout.
|
|
35
|
+
layoutsByPrefix.getOrInsert(parsed.routeSegments.join("/"), []).push(...files);
|
|
59
36
|
} else if (parsed.kind === "page") {
|
|
60
37
|
pagesBySegments.push({
|
|
61
38
|
key,
|
|
@@ -68,9 +45,7 @@ export function computeRouteSeedIndex(pageEntries: PageEntry[]): RouteSeedIndex
|
|
|
68
45
|
}
|
|
69
46
|
assertUniqueRoutePatterns(pagesBySegments);
|
|
70
47
|
|
|
71
|
-
const
|
|
72
|
-
const globalLayoutFiles = rootLayouts;
|
|
73
|
-
|
|
48
|
+
const globalLayoutFiles = layoutsByPrefix.get("") ?? [];
|
|
74
49
|
const seedEntries: RouteSeedEntry[] = [];
|
|
75
50
|
for (const { pattern, segments, files, includeOwnLayout } of pagesBySegments) {
|
|
76
51
|
const layouts: string[] = [];
|
|
@@ -84,26 +59,18 @@ export function computeRouteSeedIndex(pageEntries: PageEntry[]): RouteSeedIndex
|
|
|
84
59
|
const routeId = pattern || "/";
|
|
85
60
|
seedEntries.push({ routeId, pattern: routeId, seeds });
|
|
86
61
|
}
|
|
87
|
-
// Static segments must beat `:param` ones
|
|
88
|
-
// `/persona/new` resolves to `[personaId]=new`. Sort once at build time
|
|
89
|
-
// so the runtime matcher can stay first-match-wins.
|
|
62
|
+
// Static segments must beat `:param` ones (`/persona/new` is not `[personaId]=new`); the runtime is first-match-wins.
|
|
90
63
|
seedEntries.sort((a, b) => compareRouteSpecificity(a.pattern, b.pattern));
|
|
91
64
|
return { entries: seedEntries, globalLayoutFiles };
|
|
92
65
|
}
|
|
93
66
|
|
|
94
|
-
export const ROUTE_SEED_INDEX_JSON = "route-seed-index.json";
|
|
95
|
-
|
|
96
67
|
export function serializeRouteSeedIndexForArtifact(
|
|
97
68
|
index: RouteSeedIndex,
|
|
98
69
|
artifactDir: string,
|
|
99
70
|
options: { production?: boolean } = {},
|
|
100
71
|
): SerializedRouteSeedIndex {
|
|
101
72
|
const normalizedArtifactDir = path.resolve(artifactDir);
|
|
102
|
-
if (options.production) {
|
|
103
|
-
return {
|
|
104
|
-
entries: index.entries.map((entry) => ({ routeId: entry.routeId })),
|
|
105
|
-
};
|
|
106
|
-
}
|
|
73
|
+
if (options.production) return { entries: index.entries.map((entry) => ({ routeId: entry.routeId })) };
|
|
107
74
|
return {
|
|
108
75
|
entries: index.entries.map((entry) => ({
|
|
109
76
|
...entry,
|
package/biome.base.json
CHANGED
|
@@ -137,7 +137,8 @@
|
|
|
137
137
|
"!**/*.spec.tsx",
|
|
138
138
|
"!**/*.constant.ts",
|
|
139
139
|
"!**/common/**",
|
|
140
|
-
"!**/env/**"
|
|
140
|
+
"!**/env/**",
|
|
141
|
+
"!{apps,libs}/*/native/**"
|
|
141
142
|
],
|
|
142
143
|
"plugins": ["./node_modules/@akanjs/devkit/lint/no-throw-raw-error.grit"]
|
|
143
144
|
},
|
|
@@ -154,7 +155,12 @@
|
|
|
154
155
|
]
|
|
155
156
|
},
|
|
156
157
|
{
|
|
157
|
-
"includes": [
|
|
158
|
+
"includes": [
|
|
159
|
+
"{apps,libs}/**/page/**/*.ts",
|
|
160
|
+
"{apps,libs}/**/page/**/*.tsx",
|
|
161
|
+
"{apps,libs}/**/*.Unit.tsx",
|
|
162
|
+
"{apps,libs}/**/*.View.tsx"
|
|
163
|
+
],
|
|
158
164
|
"plugins": ["./node_modules/@akanjs/devkit/lint/non-scalar-props-restricted.grit"]
|
|
159
165
|
},
|
|
160
166
|
{
|
|
@@ -201,6 +207,33 @@
|
|
|
201
207
|
],
|
|
202
208
|
"plugins": ["./node_modules/@akanjs/devkit/lint/no-init-fetch-in-client.grit"]
|
|
203
209
|
},
|
|
210
|
+
{
|
|
211
|
+
"includes": [
|
|
212
|
+
"{apps,libs}/**/*.ts",
|
|
213
|
+
"{apps,libs}/**/*.tsx",
|
|
214
|
+
"!**/*.test.ts",
|
|
215
|
+
"!**/*.test.tsx",
|
|
216
|
+
"!**/*.spec.ts",
|
|
217
|
+
"!**/*.spec.tsx"
|
|
218
|
+
],
|
|
219
|
+
"plugins": [
|
|
220
|
+
"./node_modules/@akanjs/devkit/lint/no-document-cookie.grit",
|
|
221
|
+
"./node_modules/@akanjs/devkit/lint/no-web-storage.grit"
|
|
222
|
+
]
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"includes": [
|
|
226
|
+
"{apps,libs}/**/*.ts",
|
|
227
|
+
"{apps,libs}/**/*.tsx",
|
|
228
|
+
"!{apps,libs}/**/webkit/**",
|
|
229
|
+
"!{apps,libs}/*/native/**",
|
|
230
|
+
"!**/*.test.ts",
|
|
231
|
+
"!**/*.test.tsx",
|
|
232
|
+
"!**/*.spec.ts",
|
|
233
|
+
"!**/*.spec.tsx"
|
|
234
|
+
],
|
|
235
|
+
"plugins": ["./node_modules/@akanjs/devkit/lint/no-web-only-api-outside-webkit.grit"]
|
|
236
|
+
},
|
|
204
237
|
{
|
|
205
238
|
"includes": [
|
|
206
239
|
"**/ui/**/*.ts",
|
package/biomeBase.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/** `extends` target for a workspace `biome.json`; Biome resolves it through node_modules. */
|
|
2
2
|
export const biomeBaseConfig = "@akanjs/devkit/biome.base.json";
|
|
3
3
|
|
|
4
|
-
// Biome moves rules between groups across minors
|
|
5
|
-
// `
|
|
6
|
-
// Biome disagrees with the shipped base config therefore fails to load it at all, which is why the version is
|
|
7
|
-
// pinned here instead of resolved to latest at create time. Bump this and `biome.base.json` in one commit, and run
|
|
8
|
-
// `biome migrate --write` in the workspace root and in `pkgs/@akanjs/devkit` so both configs move together.
|
|
4
|
+
// Pinned: Biome moves rules between groups across minors and a stale position is a hard config error. Bump it with
|
|
5
|
+
// `biome.base.json` in one commit, running `biome migrate --write` in the workspace root and in this package.
|
|
9
6
|
export const biomeVersion = "2.5.12";
|