From 6103fddd45072fbf79bebd467d58a03b8d6bece6 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Sat, 24 Oct 2026 03:11:12 +0800 Subject: [PATCH] fix(javascript): scope Next package admission by container identity --- .../JavaScriptNextAppContext.test.ts | 24 +++++++++++++++++++ .../javascript/JavaScriptNextAppContext.ts | 15 +++++++----- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/application/javascript/JavaScriptNextAppContext.test.ts b/src/application/javascript/JavaScriptNextAppContext.test.ts index 53e55ae476..6bf719c752 100644 --- a/src/application/javascript/JavaScriptNextAppContext.test.ts +++ b/src/application/javascript/JavaScriptNextAppContext.test.ts @@ -15,6 +15,30 @@ const file = (path: string, text = ""): JavaScriptArtifactFile => ({ text: { included: true, value: text }, }); +it("keeps package applicability and its root cache scoped to the source container", () => { + const manifest = file("package.json", '{"dependencies":{"next":"16.4.2"}}'); + const foreign = { + ...file("package.json", '{"name":"plain"}'), + container_sha256: "c".repeat(64), + }; + const page = file("app/page.js"); + const foreignPage = { ...page, container_sha256: foreign.container_sha256 }; + const context = createJavaScriptNextAppContext( + [manifest, foreign, page, foreignPage], + new JavaScriptJsonDocuments(), + new Set(["app"]), + ); + expect(context(page)).toMatchObject({ + kind: "app-directory", + package: { container_sha256: manifest.container_sha256 }, + }); + expect(context(foreignPage)).toMatchObject({ + kind: "unknown", + package: { container_sha256: foreign.container_sha256 }, + }); + expect(context(page).kind).toBe("app-directory"); +}); + it("uses the nearest declared Next package and root directory precedence", () => { const files = [ file("package.json", '{"dependencies":{"next":"16.4.2"}}'), diff --git a/src/application/javascript/JavaScriptNextAppContext.ts b/src/application/javascript/JavaScriptNextAppContext.ts index 5f9fc75151..99cbc383fd 100644 --- a/src/application/javascript/JavaScriptNextAppContext.ts +++ b/src/application/javascript/JavaScriptNextAppContext.ts @@ -2,6 +2,7 @@ import { posix } from "node:path"; import type { JavaScriptArtifactFile } from "../../domain/javascript/javascriptArtifactFiles.js"; import type { NextAppSourceContext } from "../../domain/javascript/javascriptRoutePaths.js"; +import { compositeKey } from "../../domain/unicodeCodePointOrder.js"; import type { JavaScriptJsonDocuments } from "./JavaScriptJsonDocuments.js"; /** Package declarations and inventoried directories own source-router applicability. */ @@ -15,7 +16,10 @@ export const createJavaScriptNextAppContext = ( const packages = new Map( files .filter(({ kind }) => kind === "package-json") - .map((file) => [posix.dirname(file.path), file]), + .map((file) => [ + compositeKey([file.container_sha256, posix.dirname(file.path)]), + file, + ]), ); const roots = new Map(); return (file) => { @@ -24,11 +28,10 @@ export const createJavaScriptNextAppContext = ( ; directory = posix.dirname(directory) ) { - const manifest = packages.get(directory); - if ( - manifest !== undefined && - manifest.container_sha256 === file.container_sha256 - ) { + const manifest = packages.get( + compositeKey([file.container_sha256, directory]), + ); + if (manifest !== undefined) { const identity = { path: manifest.path, sha256: manifest.sha256,