@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
|
@@ -3,17 +3,12 @@ import type { BunPlugin } from "bun";
|
|
|
3
3
|
import ts from "typescript";
|
|
4
4
|
import type { App } from "../commandDecorators";
|
|
5
5
|
import { BarrelAnalyzer, type BarrelExportMap, type PackageEntry } from "./barrelAnalyzer";
|
|
6
|
+
import { loaderFor, type NamedItem, parseNamedList } from "./moduleSyntax";
|
|
6
7
|
|
|
7
8
|
export interface BarrelImportsPluginOptions {
|
|
8
|
-
/** Absolute paths whose content
|
|
9
|
+
/** Absolute paths whose content is returned unchanged (e.g. node_modules). */
|
|
9
10
|
skipPath?: (absPath: string) => boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Optional transform applied after the barrel rewrite in the same onLoad
|
|
12
|
-
* pass. Useful to chain further transforms (e.g. `"use client"` stubbing)
|
|
13
|
-
* that would otherwise be blocked — Bun's `onLoad` cannot fall through to a
|
|
14
|
-
* second plugin once a response is returned.
|
|
15
|
-
* Return the transformed source, or `null` to indicate no change.
|
|
16
|
-
*/
|
|
11
|
+
/** Runs after the rewrite in the same onLoad (Bun's onLoad cannot fall through); null means no change. */
|
|
17
12
|
pipeAfter?: (source: string, args: { path: string }) => string | Promise<string | null> | null;
|
|
18
13
|
}
|
|
19
14
|
|
|
@@ -30,13 +25,8 @@ export const createBarrelImportsPlugin = async (
|
|
|
30
25
|
return {
|
|
31
26
|
name: "barrel-imports",
|
|
32
27
|
setup(build) {
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
// The optional `(\?v=\d+)?` tail lets the filter match paths that HMR
|
|
37
|
-
// has version-tagged (`./_index.tsx?v=3`). We strip the query before
|
|
38
|
-
// reading and normalize it away from the path we pass downstream so
|
|
39
|
-
// only the cache-bust `pipeAfter` step (if any) knows about it.
|
|
28
|
+
// node_modules/akanjs stays in: framework `"use client"` modules still need RSC stubbing in generated workspaces.
|
|
29
|
+
// The optional `?v=N` tail matches HMR cache-busted paths; it is stripped before reading.
|
|
40
30
|
build.onLoad(
|
|
41
31
|
{
|
|
42
32
|
filter:
|
|
@@ -45,27 +35,12 @@ export const createBarrelImportsPlugin = async (
|
|
|
45
35
|
async (args) => {
|
|
46
36
|
const realPath = args.path.replace(/\?v=\d+$/, "");
|
|
47
37
|
const loader = loaderFor(realPath);
|
|
48
|
-
if (skipPath(realPath)) {
|
|
49
|
-
const raw = await Bun.file(realPath).text();
|
|
50
|
-
return { contents: raw, loader };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
38
|
let source = await Bun.file(realPath).text();
|
|
39
|
+
if (skipPath(realPath)) return { contents: source, loader };
|
|
54
40
|
|
|
55
|
-
// Bun's macro evaluator
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
// being evaluated concurrently in the same graph: one of the macro
|
|
59
|
-
// identifiers ends up undefined at runtime (e.g. `getSerializedSignal
|
|
60
|
-
// is not defined`). Returning the unmodified source for macro hosts
|
|
61
|
-
// sidesteps the race. The trade-off is that a handful of `useClient`-
|
|
62
|
-
// style files keep their original barrel imports; the rest of the
|
|
63
|
-
// tree still benefits from flattening.
|
|
64
|
-
const hasMacroAttr = MACRO_ATTR_RE.test(source);
|
|
65
|
-
|
|
66
|
-
if (!hasMacroAttr && barrels.length > 0) {
|
|
67
|
-
// The pre-check that used to live here — "does this file mention a barrel at all" — now
|
|
68
|
-
// lives inside `rewriteBarrelImports`, so every caller gets it rather than just this one.
|
|
41
|
+
// Bun's macro evaluator races when a rewritten module holds `with { type: "macro" }` imports while another
|
|
42
|
+
// macro host evaluates (a macro identifier ends up undefined), so macro hosts keep their barrel imports.
|
|
43
|
+
if (!MACRO_ATTR_RE.test(source) && barrels.length > 0) {
|
|
69
44
|
const rewritten = await rewriteBarrelImports(source, barrels, analyzer);
|
|
70
45
|
if (rewritten !== null) source = rewritten;
|
|
71
46
|
}
|
|
@@ -82,24 +57,16 @@ export const createBarrelImportsPlugin = async (
|
|
|
82
57
|
};
|
|
83
58
|
};
|
|
84
59
|
|
|
85
|
-
/**
|
|
86
|
-
* Build a `resolvePackage` that maps a package specifier (like `akanjs/ui`)
|
|
87
|
-
* to its barrel entry file using the workspace tsconfig `paths`. If no direct
|
|
88
|
-
* mapping exists, falls back to node_modules resolution.
|
|
89
|
-
*/
|
|
60
|
+
/** Resolves a package specifier to its barrel entry via tsconfig `paths`, falling back to node_modules. */
|
|
90
61
|
export const createTsconfigPackageResolver = async (
|
|
91
62
|
app: App,
|
|
92
63
|
): Promise<(pkgName: string) => Promise<PackageEntry | null>> => {
|
|
93
64
|
const tsconfig = await app.getTsConfig();
|
|
94
65
|
const tsconfigPaths = tsconfig.compilerOptions.paths ?? {};
|
|
95
|
-
//
|
|
96
|
-
// Longer prefixes sort first so `@libs/util/*` wins over `@libs/*`.
|
|
66
|
+
// Longest prefix first so `@libs/util/*` wins over `@libs/*`.
|
|
97
67
|
const wildcardEntries = Object.entries(tsconfigPaths)
|
|
98
68
|
.filter(([k]) => k.endsWith("/*"))
|
|
99
|
-
.map(([k, v]) => ({
|
|
100
|
-
prefix: k.slice(0, -1), // keep trailing `/`
|
|
101
|
-
replacements: v,
|
|
102
|
-
}))
|
|
69
|
+
.map(([k, v]) => ({ prefix: k.slice(0, -1), replacements: v }))
|
|
103
70
|
.sort((a, b) => b.prefix.length - a.prefix.length);
|
|
104
71
|
|
|
105
72
|
return async (pkgName) => {
|
|
@@ -109,34 +76,16 @@ export const createTsconfigPackageResolver = async (
|
|
|
109
76
|
if (!raw) return null;
|
|
110
77
|
const entryFile = path.resolve(app.workspace.workspaceRoot, raw);
|
|
111
78
|
if (!(await Bun.file(entryFile).exists())) return null;
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
// rather than an `index.*` inside a dedicated package directory
|
|
115
|
-
// (`libs/util/server/index.ts`). For facets, the subpath the analyzer
|
|
116
|
-
// generates for a leaf like `libs/util/lib/sig.ts` must be computed
|
|
117
|
-
// against the parent package (`@libs/util`) so that the rewritten
|
|
118
|
-
// import resolves via the workspace's `@libs/*` tsconfig wildcard
|
|
119
|
-
// (`libs/util/lib/sig`). Using the raw `pkgName` (`@libs/util/server`)
|
|
120
|
-
// would generate `@libs/util/server/lib/sig`, a path that does not exist
|
|
121
|
-
// on disk and cannot be imported.
|
|
79
|
+
// A facet barrel (`@libs/util/server` -> `libs/util/server.ts`) takes subpaths from its parent package, so a leaf
|
|
80
|
+
// rewrites to `@libs/util/lib/sig` (resolvable via `@libs/*`), not the missing `@libs/util/server/lib/sig`.
|
|
122
81
|
const parsed = path.parse(entryFile);
|
|
123
82
|
const lastSlash = pkgName.lastIndexOf("/");
|
|
124
|
-
if (parsed.name !== "index" && lastSlash
|
|
125
|
-
|
|
126
|
-
const parentSpec = pkgName.slice(0, lastSlash);
|
|
127
|
-
if (facet === parsed.name && parentSpec.length > 0) {
|
|
128
|
-
return { pkgName: parentSpec, entryFile, pkgDir: parsed.dir };
|
|
129
|
-
}
|
|
130
|
-
}
|
|
83
|
+
if (parsed.name !== "index" && lastSlash > 0 && pkgName.slice(lastSlash + 1) === parsed.name)
|
|
84
|
+
return { pkgName: pkgName.slice(0, lastSlash), entryFile, pkgDir: parsed.dir };
|
|
131
85
|
return { pkgName, entryFile, pkgDir: path.dirname(entryFile) };
|
|
132
86
|
}
|
|
133
87
|
|
|
134
|
-
//
|
|
135
|
-
// whole family of specifiers to workspace directories. Without this,
|
|
136
|
-
// barrels such as `@libs/util/ui` or `@apps/minimal/client` never resolve
|
|
137
|
-
// to an entry file — the analyzer returns `null`, the plugin skips them,
|
|
138
|
-
// and the consumer falls back to Bun's default resolution which loads the
|
|
139
|
-
// full barrel (pulling the entire transitive macro / side-effect graph).
|
|
88
|
+
// Without the wildcard fallback `@libs/util/ui`-style barrels never resolve and load whole, macro graph included.
|
|
140
89
|
for (const { prefix, replacements } of wildcardEntries) {
|
|
141
90
|
if (!pkgName.startsWith(prefix)) continue;
|
|
142
91
|
const suffix = pkgName.slice(prefix.length);
|
|
@@ -144,41 +93,25 @@ export const createTsconfigPackageResolver = async (
|
|
|
144
93
|
if (!repl) continue;
|
|
145
94
|
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
146
95
|
const candidate = path.resolve(app.workspace.workspaceRoot, replPath + suffix);
|
|
147
|
-
//
|
|
148
|
-
// `apps/minimal/client.ts`). If it exists we treat the PARENT directory
|
|
149
|
-
// as `pkgDir` and the PARENT specifier (`@apps/minimal`) as `pkgName`
|
|
150
|
-
// so a leaf at `apps/minimal/lib/useClient.ts` rewrites to
|
|
151
|
-
// `@apps/minimal/lib/useClient` and resolves via the same `@apps/*`
|
|
152
|
-
// wildcard. Using the raw `pkgName` would yield
|
|
153
|
-
// `@apps/minimal/client/lib/useClient`, a path that does not exist.
|
|
96
|
+
// A sibling file (`apps/minimal/client.ts`) is a facet barrel too: parent specifier, as above.
|
|
154
97
|
for (const ext of CANDIDATE_EXTS) {
|
|
155
98
|
const file = `${candidate}${ext}`;
|
|
156
99
|
if (await Bun.file(file).exists()) {
|
|
157
100
|
const lastSlash = pkgName.lastIndexOf("/");
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (parentSpec.length > 0) {
|
|
161
|
-
return { pkgName: parentSpec, entryFile: file, pkgDir: path.dirname(file) };
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return { pkgName, entryFile: file, pkgDir: path.dirname(file) };
|
|
101
|
+
const parentSpec = lastSlash > 0 ? pkgName.slice(0, lastSlash) : pkgName;
|
|
102
|
+
return { pkgName: parentSpec, entryFile: file, pkgDir: path.dirname(file) };
|
|
165
103
|
}
|
|
166
104
|
}
|
|
167
105
|
for (const ext of CANDIDATE_EXTS) {
|
|
168
106
|
const file = path.join(candidate, `index${ext}`);
|
|
169
|
-
if (await Bun.file(file).exists()) {
|
|
170
|
-
return { pkgName, entryFile: file, pkgDir: candidate };
|
|
171
|
-
}
|
|
107
|
+
if (await Bun.file(file).exists()) return { pkgName, entryFile: file, pkgDir: candidate };
|
|
172
108
|
}
|
|
173
109
|
}
|
|
174
|
-
// A prefix
|
|
175
|
-
// prefix doesn't accidentally resolve to an unrelated location.
|
|
110
|
+
// A matched prefix with nothing on disk stops here, so a shorter prefix cannot resolve somewhere unrelated.
|
|
176
111
|
return null;
|
|
177
112
|
}
|
|
178
113
|
|
|
179
|
-
//
|
|
180
|
-
// single-package subpaths such as `akanjs/ui`, whose package.json lives at
|
|
181
|
-
// node_modules/akanjs/package.json rather than node_modules/akanjs/ui.
|
|
114
|
+
// `akanjs/ui` resolves through node_modules/akanjs/package.json exports, not node_modules/akanjs/ui.
|
|
182
115
|
const exported = await resolveNodePackageExport(app.workspace.workspaceRoot, pkgName);
|
|
183
116
|
if (exported) return exported;
|
|
184
117
|
|
|
@@ -226,8 +159,7 @@ const resolveNodePackageExport = async (workspaceRoot: string, specifier: string
|
|
|
226
159
|
if (!rel?.startsWith(".")) return null;
|
|
227
160
|
const entryFile = await resolveFileCandidate(path.resolve(pkgDir, rel));
|
|
228
161
|
if (!entryFile) return null;
|
|
229
|
-
|
|
230
|
-
return { pkgName: pkgEntryName, entryFile, pkgDir: path.dirname(entryFile), preserveFilePath: true };
|
|
162
|
+
return { pkgName: specifier, entryFile, pkgDir: path.dirname(entryFile), preserveFilePath: true };
|
|
231
163
|
} catch {
|
|
232
164
|
return null;
|
|
233
165
|
}
|
|
@@ -290,22 +222,14 @@ const resolveFileCandidate = async (candidate: string): Promise<string | null> =
|
|
|
290
222
|
return null;
|
|
291
223
|
};
|
|
292
224
|
|
|
293
|
-
// Matches `with { type: "macro" }` import attributes (single or double quotes,
|
|
294
|
-
// tolerant of whitespace). Used to detect macro-host modules so the plugin
|
|
295
|
-
// can leave their source untouched.
|
|
296
225
|
const MACRO_ATTR_RE = /with\s*\{\s*type\s*:\s*["']macro["']\s*\}/;
|
|
297
226
|
|
|
298
|
-
/** Exposed for testing. */
|
|
299
227
|
export const rewriteBarrelImports = async (
|
|
300
228
|
source: string,
|
|
301
229
|
barrels: string[],
|
|
302
230
|
analyzer: BarrelAnalyzer,
|
|
303
231
|
): Promise<string | null> => {
|
|
304
|
-
//
|
|
305
|
-
// every source file of every dev rebuild, and parsing was by far the most expensive thing in one:
|
|
306
|
-
// measured across 1189 files here, 299ms and 161MB of RSS, of which **63% of files import no barrel
|
|
307
|
-
// at all**. A static import cannot name a specifier without that specifier appearing literally in the
|
|
308
|
-
// text, so a substring test is a sound filter and costs 4ms for the whole corpus.
|
|
232
|
+
// Sound pre-filter before the costly parse: a static import cannot name a specifier absent from the text.
|
|
309
233
|
if (!barrels.some((barrel) => source.includes(barrel))) return null;
|
|
310
234
|
const statements = findImportStatements(source);
|
|
311
235
|
if (statements.length === 0) return null;
|
|
@@ -332,15 +256,11 @@ interface ImportStatement {
|
|
|
332
256
|
end: number;
|
|
333
257
|
clause: string;
|
|
334
258
|
specifier: string;
|
|
335
|
-
trailingSemicolon: boolean;
|
|
336
|
-
raw: string;
|
|
337
259
|
}
|
|
338
260
|
|
|
339
261
|
const findImportStatements = (source: string): ImportStatement[] => {
|
|
340
262
|
const statements: ImportStatement[] = [];
|
|
341
|
-
// `setParentNodes: false
|
|
342
|
-
// `getStart(sourceFile)`, which takes the file explicitly. Building the parent links cost 132ms and
|
|
343
|
-
// 143MB of RSS across 1189 files for no reader.
|
|
263
|
+
// `setParentNodes: false` holds only while nothing reads `node.parent` and positions use `getStart(sourceFile)`.
|
|
344
264
|
const sourceFile = ts.createSourceFile(
|
|
345
265
|
"barrel-imports.tsx",
|
|
346
266
|
source,
|
|
@@ -353,31 +273,20 @@ const findImportStatements = (source: string): ImportStatement[] => {
|
|
|
353
273
|
if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
|
|
354
274
|
const importClause = statement.importClause;
|
|
355
275
|
if (!importClause) continue;
|
|
356
|
-
const statementStart = statement.getStart(sourceFile);
|
|
357
|
-
const statementEnd = statement.end;
|
|
358
276
|
statements.push({
|
|
359
|
-
start:
|
|
360
|
-
end:
|
|
277
|
+
start: statement.getStart(sourceFile),
|
|
278
|
+
end: statement.end,
|
|
361
279
|
clause: source.slice(importClause.getStart(sourceFile), importClause.end).trim(),
|
|
362
280
|
specifier: statement.moduleSpecifier.text,
|
|
363
|
-
trailingSemicolon: source.slice(statement.moduleSpecifier.end, statement.end).includes(";"),
|
|
364
|
-
raw: source.slice(statementStart, statementEnd),
|
|
365
281
|
});
|
|
366
282
|
}
|
|
367
283
|
return statements;
|
|
368
284
|
};
|
|
369
285
|
|
|
370
|
-
interface NamedImportItem {
|
|
371
|
-
imported: string;
|
|
372
|
-
local: string;
|
|
373
|
-
isType: boolean;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
286
|
interface ParsedClause {
|
|
377
287
|
defaultImport?: string;
|
|
378
288
|
namespaceImport?: string;
|
|
379
|
-
named?:
|
|
380
|
-
/** Whole clause is `import type { ... } from "..."`. */
|
|
289
|
+
named?: NamedItem[];
|
|
381
290
|
typeOnly: boolean;
|
|
382
291
|
}
|
|
383
292
|
|
|
@@ -389,7 +298,6 @@ const parseImportClause = (clause: string): ParsedClause | null => {
|
|
|
389
298
|
rest = rest.slice(5).trim();
|
|
390
299
|
}
|
|
391
300
|
const parsed: ParsedClause = { typeOnly };
|
|
392
|
-
// Try pattern: default + rest
|
|
393
301
|
const commaMatch = /^(\w+)\s*,\s*(.+)$/.exec(rest);
|
|
394
302
|
if (commaMatch) {
|
|
395
303
|
parsed.defaultImport = commaMatch[1];
|
|
@@ -407,36 +315,11 @@ const parseImportClause = (clause: string): ParsedClause | null => {
|
|
|
407
315
|
if (rest.startsWith("{")) {
|
|
408
316
|
const close = rest.indexOf("}");
|
|
409
317
|
if (close === -1) return null;
|
|
410
|
-
|
|
411
|
-
parsed.named = parseNamedImportList(inner);
|
|
412
|
-
return parsed;
|
|
318
|
+
parsed.named = parseNamedList(rest.slice(1, close));
|
|
413
319
|
}
|
|
414
320
|
return parsed;
|
|
415
321
|
};
|
|
416
322
|
|
|
417
|
-
const parseNamedImportList = (body: string): NamedImportItem[] => {
|
|
418
|
-
const out: NamedImportItem[] = [];
|
|
419
|
-
for (const raw of body.split(",")) {
|
|
420
|
-
const s = raw.trim();
|
|
421
|
-
if (!s) continue;
|
|
422
|
-
let isType = false;
|
|
423
|
-
let rest = s;
|
|
424
|
-
if (rest.startsWith("type ")) {
|
|
425
|
-
isType = true;
|
|
426
|
-
rest = rest.slice(5).trim();
|
|
427
|
-
}
|
|
428
|
-
const asMatch = /^(\w+)\s+as\s+(\w+)$/.exec(rest);
|
|
429
|
-
if (asMatch) {
|
|
430
|
-
out.push({ imported: asMatch[1] ?? "", local: asMatch[2] ?? "", isType });
|
|
431
|
-
continue;
|
|
432
|
-
}
|
|
433
|
-
if (/^\w+$/.test(rest)) {
|
|
434
|
-
out.push({ imported: rest, local: rest, isType });
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
return out;
|
|
438
|
-
};
|
|
439
|
-
|
|
440
323
|
const rewriteSingleStatement = (stmt: ImportStatement, map: BarrelExportMap): string | null => {
|
|
441
324
|
const clause = parseImportClause(stmt.clause);
|
|
442
325
|
if (!clause) return null;
|
|
@@ -444,13 +327,10 @@ const rewriteSingleStatement = (stmt: ImportStatement, map: BarrelExportMap): st
|
|
|
444
327
|
if (clause.namespaceImport) return null;
|
|
445
328
|
// Pure type imports are erased at build; leave them alone.
|
|
446
329
|
if (clause.typeOnly && !clause.defaultImport) return null;
|
|
447
|
-
if (!clause.named
|
|
448
|
-
// Only default import — nothing to split.
|
|
449
|
-
return null;
|
|
450
|
-
}
|
|
330
|
+
if (!clause.named?.length) return null;
|
|
451
331
|
|
|
452
|
-
const remaining:
|
|
453
|
-
const rewrites = new Map<string,
|
|
332
|
+
const remaining: NamedItem[] = [];
|
|
333
|
+
const rewrites = new Map<string, NamedItem[]>();
|
|
454
334
|
for (const item of clause.named) {
|
|
455
335
|
if (item.isType) {
|
|
456
336
|
remaining.push(item);
|
|
@@ -462,7 +342,6 @@ const rewriteSingleStatement = (stmt: ImportStatement, map: BarrelExportMap): st
|
|
|
462
342
|
continue;
|
|
463
343
|
}
|
|
464
344
|
const list = rewrites.get(target.subpath) ?? [];
|
|
465
|
-
// Use the leaf's original name, keeping the consumer's local alias.
|
|
466
345
|
list.push({ imported: target.originalName, local: item.local, isType: false });
|
|
467
346
|
rewrites.set(target.subpath, list);
|
|
468
347
|
}
|
|
@@ -470,26 +349,17 @@ const rewriteSingleStatement = (stmt: ImportStatement, map: BarrelExportMap): st
|
|
|
470
349
|
if (rewrites.size === 0) return null;
|
|
471
350
|
|
|
472
351
|
const lines: string[] = [];
|
|
473
|
-
|
|
474
|
-
const tail = ";";
|
|
352
|
+
if (shouldPreserveBarrelSideEffects(stmt.specifier)) lines.push(`import "${stmt.specifier}";`);
|
|
475
353
|
|
|
476
|
-
if (shouldPreserveBarrelSideEffects(stmt.specifier)) {
|
|
477
|
-
lines.push(`import "${stmt.specifier}"${tail}`);
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
// Re-emit an import from the original barrel that carries whatever we could
|
|
481
|
-
// not flatten (default import, type-only items, unknown names).
|
|
482
354
|
if (clause.defaultImport || remaining.length > 0) {
|
|
483
355
|
const parts: string[] = [];
|
|
484
356
|
if (clause.defaultImport) parts.push(clause.defaultImport);
|
|
485
|
-
if (remaining.length > 0) {
|
|
486
|
-
|
|
487
|
-
}
|
|
488
|
-
lines.push(`import ${parts.join(", ")} from "${stmt.specifier}"${tail}`);
|
|
357
|
+
if (remaining.length > 0) parts.push(`{ ${remaining.map(serializeNamedItem).join(", ")} }`);
|
|
358
|
+
lines.push(`import ${parts.join(", ")} from "${stmt.specifier}";`);
|
|
489
359
|
}
|
|
490
360
|
|
|
491
361
|
for (const [subpath, items] of rewrites) {
|
|
492
|
-
lines.push(`import { ${items.map(serializeNamedItem).join(", ")} } from "${subpath}"
|
|
362
|
+
lines.push(`import { ${items.map(serializeNamedItem).join(", ")} } from "${subpath}";`);
|
|
493
363
|
}
|
|
494
364
|
|
|
495
365
|
return lines.join("\n");
|
|
@@ -497,15 +367,8 @@ const rewriteSingleStatement = (stmt: ImportStatement, map: BarrelExportMap): st
|
|
|
497
367
|
|
|
498
368
|
const shouldPreserveBarrelSideEffects = (specifier: string): boolean => /^@(apps|libs)\/[^/]+\/client$/.test(specifier);
|
|
499
369
|
|
|
500
|
-
const serializeNamedItem = (item:
|
|
370
|
+
const serializeNamedItem = (item: NamedItem): string => {
|
|
501
371
|
const prefix = item.isType ? "type " : "";
|
|
502
372
|
if (item.imported === item.local) return `${prefix}${item.imported}`;
|
|
503
373
|
return `${prefix}${item.imported} as ${item.local}`;
|
|
504
374
|
};
|
|
505
|
-
|
|
506
|
-
const loaderFor = (absPath: string): "ts" | "tsx" | "js" | "jsx" => {
|
|
507
|
-
if (absPath.endsWith(".tsx")) return "tsx";
|
|
508
|
-
if (absPath.endsWith(".jsx")) return "jsx";
|
|
509
|
-
if (absPath.endsWith(".ts")) return "ts";
|
|
510
|
-
return "js";
|
|
511
|
-
};
|
|
@@ -1,70 +1,46 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
3
|
-
import os from "node:os";
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
4
2
|
import path from "node:path";
|
|
3
|
+
import { tempDirs, writeText as write } from "../testHelpers";
|
|
5
4
|
import { createExternalizeFrameworkPlugin } from "./externalizeFrameworkPlugin";
|
|
6
5
|
|
|
7
|
-
const
|
|
6
|
+
const makeTempRoot = tempDirs("akan-devkit-externalize-");
|
|
8
7
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
const akanServerPaths = {
|
|
9
|
+
akanjs: ["./pkgs/akanjs/index.ts"],
|
|
10
|
+
"akanjs/*": ["./pkgs/akanjs/*"],
|
|
11
|
+
"akanjs/server": ["./pkgs/akanjs/server/index.ts"],
|
|
12
|
+
"akanjs/server/*": ["./pkgs/akanjs/server/*"],
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
await
|
|
15
|
+
const bundle = async (root: string, paths: Record<string, string[]>, entryLines: string[]) => {
|
|
16
|
+
const entry = path.join(root, "entry.ts");
|
|
17
|
+
await write(entry, [...entryLines, ""].join("\n"));
|
|
18
|
+
const plugin = await createExternalizeFrameworkPlugin({
|
|
19
|
+
app: { workspace: { workspaceRoot: root }, getTsConfig: async () => ({ compilerOptions: { paths } }) } as never,
|
|
20
|
+
});
|
|
21
|
+
const result = await Bun.build({
|
|
22
|
+
entrypoints: [entry],
|
|
23
|
+
outdir: path.join(root, "out"),
|
|
24
|
+
target: "bun",
|
|
25
|
+
format: "esm",
|
|
26
|
+
plugins: [plugin],
|
|
27
|
+
});
|
|
28
|
+
expect(result.success).toBe(true);
|
|
29
|
+
return await result.outputs.find((artifact) => artifact.kind === "entry-point")?.text();
|
|
18
30
|
};
|
|
19
31
|
|
|
20
|
-
afterEach(async () => {
|
|
21
|
-
await Promise.all(tempRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
|
|
22
|
-
});
|
|
23
|
-
|
|
24
32
|
describe("createExternalizeFrameworkPlugin", () => {
|
|
25
33
|
test("bundles akanjs/server workspace sources into production pages artifacts", async () => {
|
|
26
34
|
const root = await makeTempRoot();
|
|
27
|
-
const entry = path.join(root, "entry.ts");
|
|
28
|
-
const outdir = path.join(root, "out");
|
|
29
|
-
await write(
|
|
30
|
-
entry,
|
|
31
|
-
[
|
|
32
|
-
'import { optionMarker } from "akanjs/server";',
|
|
33
|
-
'import { tryMarker } from "akanjs/server/decorators";',
|
|
34
|
-
'import { jsx } from "react/jsx-runtime";',
|
|
35
|
-
"export const markers = [optionMarker, tryMarker, jsx];",
|
|
36
|
-
"",
|
|
37
|
-
].join("\n"),
|
|
38
|
-
);
|
|
39
35
|
await write(path.join(root, "pkgs/akanjs/server/index.ts"), 'export const optionMarker = "akan-option";\n');
|
|
40
36
|
await write(path.join(root, "pkgs/akanjs/server/decorators.ts"), 'export const tryMarker = "akan-try";\n');
|
|
41
37
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
akanjs: ["./pkgs/akanjs/index.ts"],
|
|
49
|
-
"akanjs/*": ["./pkgs/akanjs/*"],
|
|
50
|
-
"akanjs/server": ["./pkgs/akanjs/server/index.ts"],
|
|
51
|
-
"akanjs/server/*": ["./pkgs/akanjs/server/*"],
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
}),
|
|
55
|
-
} as never,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const result = await Bun.build({
|
|
59
|
-
entrypoints: [entry],
|
|
60
|
-
outdir,
|
|
61
|
-
target: "bun",
|
|
62
|
-
format: "esm",
|
|
63
|
-
plugins: [plugin],
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
expect(result.success).toBe(true);
|
|
67
|
-
const output = await result.outputs.find((artifact) => artifact.kind === "entry-point")?.text();
|
|
38
|
+
const output = await bundle(root, akanServerPaths, [
|
|
39
|
+
'import { optionMarker } from "akanjs/server";',
|
|
40
|
+
'import { tryMarker } from "akanjs/server/decorators";',
|
|
41
|
+
'import { jsx } from "react/jsx-runtime";',
|
|
42
|
+
"export const markers = [optionMarker, tryMarker, jsx];",
|
|
43
|
+
]);
|
|
68
44
|
expect(output).toContain("akan-option");
|
|
69
45
|
expect(output).toContain("akan-try");
|
|
70
46
|
expect(output).not.toMatch(/from\s+["']akanjs\/server(?:\/decorators)?["']/);
|
|
@@ -73,17 +49,6 @@ describe("createExternalizeFrameworkPlugin", () => {
|
|
|
73
49
|
|
|
74
50
|
test("externalizes optional backend dependencies reached through bundled akanjs/server sources", async () => {
|
|
75
51
|
const root = await makeTempRoot();
|
|
76
|
-
const entry = path.join(root, "entry.ts");
|
|
77
|
-
const outdir = path.join(root, "out");
|
|
78
|
-
await write(
|
|
79
|
-
entry,
|
|
80
|
-
[
|
|
81
|
-
'import { optionMarker, redisLoader } from "akanjs/server";',
|
|
82
|
-
"export const marker = optionMarker;",
|
|
83
|
-
"export const loader = redisLoader;",
|
|
84
|
-
"",
|
|
85
|
-
].join("\n"),
|
|
86
|
-
);
|
|
87
52
|
await write(
|
|
88
53
|
path.join(root, "pkgs/akanjs/server/index.ts"),
|
|
89
54
|
[
|
|
@@ -99,32 +64,11 @@ describe("createExternalizeFrameworkPlugin", () => {
|
|
|
99
64
|
'export const loadRedis = async () => import("ioredis");\n',
|
|
100
65
|
);
|
|
101
66
|
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
paths: {
|
|
108
|
-
akanjs: ["./pkgs/akanjs/index.ts"],
|
|
109
|
-
"akanjs/*": ["./pkgs/akanjs/*"],
|
|
110
|
-
"akanjs/server": ["./pkgs/akanjs/server/index.ts"],
|
|
111
|
-
"akanjs/server/*": ["./pkgs/akanjs/server/*"],
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
}),
|
|
115
|
-
} as never,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
const result = await Bun.build({
|
|
119
|
-
entrypoints: [entry],
|
|
120
|
-
outdir,
|
|
121
|
-
target: "bun",
|
|
122
|
-
format: "esm",
|
|
123
|
-
plugins: [plugin],
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
expect(result.success).toBe(true);
|
|
127
|
-
const output = await result.outputs.find((artifact) => artifact.kind === "entry-point")?.text();
|
|
67
|
+
const output = await bundle(root, akanServerPaths, [
|
|
68
|
+
'import { optionMarker, redisLoader } from "akanjs/server";',
|
|
69
|
+
"export const marker = optionMarker;",
|
|
70
|
+
"export const loader = redisLoader;",
|
|
71
|
+
]);
|
|
128
72
|
expect(output).toContain("akan-option");
|
|
129
73
|
expect(output).toContain("ioredis");
|
|
130
74
|
expect(output).not.toMatch(/from\s+["']akanjs\/(?:server|service)["']/);
|
|
@@ -132,17 +76,6 @@ describe("createExternalizeFrameworkPlugin", () => {
|
|
|
132
76
|
|
|
133
77
|
test("lets published akanjs package exports resolve when workspace paths are absent", async () => {
|
|
134
78
|
const root = await makeTempRoot();
|
|
135
|
-
const entry = path.join(root, "entry.ts");
|
|
136
|
-
const outdir = path.join(root, "out");
|
|
137
|
-
await write(
|
|
138
|
-
entry,
|
|
139
|
-
[
|
|
140
|
-
'import { optionMarker } from "akanjs/server";',
|
|
141
|
-
'import { jsx } from "react/jsx-runtime";',
|
|
142
|
-
"export const markers = [optionMarker, jsx];",
|
|
143
|
-
"",
|
|
144
|
-
].join("\n"),
|
|
145
|
-
);
|
|
146
79
|
await write(
|
|
147
80
|
path.join(root, "node_modules/akanjs/package.json"),
|
|
148
81
|
JSON.stringify({
|
|
@@ -161,23 +94,11 @@ describe("createExternalizeFrameworkPlugin", () => {
|
|
|
161
94
|
'export const optionMarker = "published-option";\n',
|
|
162
95
|
);
|
|
163
96
|
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
const result = await Bun.build({
|
|
172
|
-
entrypoints: [entry],
|
|
173
|
-
outdir,
|
|
174
|
-
target: "bun",
|
|
175
|
-
format: "esm",
|
|
176
|
-
plugins: [plugin],
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
expect(result.success).toBe(true);
|
|
180
|
-
const output = await result.outputs.find((artifact) => artifact.kind === "entry-point")?.text();
|
|
97
|
+
const output = await bundle(root, {}, [
|
|
98
|
+
'import { optionMarker } from "akanjs/server";',
|
|
99
|
+
'import { jsx } from "react/jsx-runtime";',
|
|
100
|
+
"export const markers = [optionMarker, jsx];",
|
|
101
|
+
]);
|
|
181
102
|
expect(output).toContain("published-option");
|
|
182
103
|
expect(output).not.toMatch(/from\s+["']akanjs\/server["']/);
|
|
183
104
|
expect(output).toContain("react/jsx-runtime");
|