Skip to content

Commit 6135e07

Browse files
authored
fix(core): treat trailing-slash directories as the same Location (#59327)
1 parent 3a7ba7a commit 6135e07

4 files changed

Lines changed: 37 additions & 3 deletions

File tree

‎packages/core/src/location-service-map.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ export const reload = Effect.fn("LocationServiceMap.reload")(function* () {
3737

3838
/** Normalize equivalent placements before they become resource-cache keys. */
3939
export function canonical(ref: Location.Ref) {
40+
// Workspace refs can hold remote POSIX paths even on a Windows host.
41+
const flavor = process.platform === "win32" && !ref.directory.startsWith("/") ? path.win32 : path.posix
42+
const normalized = flavor.normalize(ref.directory)
43+
const trailing = normalized.endsWith(flavor.sep) && normalized.length > flavor.parse(normalized).root.length
4044
return Location.Ref.make({
41-
directory: AbsolutePath.make(process.platform === "win32" ? path.normalize(ref.directory) : ref.directory),
45+
directory: AbsolutePath.make(trailing ? normalized.slice(0, -1) : normalized),
4246
workspaceID: ref.workspaceID,
4347
})
4448
}

‎packages/core/src/session.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ const layer = Layer.effect(
300300
if (recorded) return recorded
301301
const parent = input.parentID ? yield* store.get(input.parentID) : undefined
302302
if (input.parentID && parent === undefined) return yield* new NotFoundError({ sessionID: input.parentID })
303-
const location = parent?.location ?? input.location
303+
const location = parent?.location ?? (input.location && LocationServiceMap.canonical(input.location))
304304
if (location === undefined)
305305
return yield* Effect.die(new Error("Session.create requires either location or an existing parentID"))
306306
const project = yield* projects.resolve(location.directory)

‎packages/core/test/location-layer.test.ts‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,23 @@ describe("LocationServiceMap", () => {
419419
Location.Ref.make({ directory, workspaceID: undefined }),
420420
])
421421

422+
const variants = [
423+
`${directory}${path.sep}`,
424+
`${directory}${path.sep}${path.sep}`,
425+
`${path.dirname(directory)}${path.sep}${path.sep}${path.basename(directory)}`,
426+
`${directory}${path.sep}.${path.sep}child${path.sep}..${path.sep}`,
427+
]
428+
for (const variant of variants) {
429+
const ref = Location.Ref.make({ directory: AbsolutePath.make(variant) })
430+
expect(LocationServiceMap.canonical(ref).directory).toBe(directory)
431+
expect(yield* locations.contextEffect(ref)).toBe(first)
432+
}
433+
expect(Array.from(yield* RcMap.keys(locations.rcMap))).toHaveLength(1)
434+
const root = path.parse(directory).root
435+
expect(
436+
LocationServiceMap.canonical(Location.Ref.make({ directory: AbsolutePath.make(root) })).directory,
437+
).toBe(AbsolutePath.make(root))
438+
422439
// Invalidating with the shape opposite to the one that booted must evict.
423440
yield* locations.invalidate(present)
424441
expect(yield* locations.contextEffectOption(absent)).toEqual(Option.none())

‎packages/core/test/session-create.test.ts‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ describe("Session.create", () => {
246246
})
247247
expect(aliasAdopted).toMatchObject({
248248
projectID: project.id,
249-
location: aliased,
249+
location: nested,
250250
subpath: RelativePath.make("packages/app"),
251251
})
252252
// Adoption is a project-domain fact; the session log records nothing new.
@@ -351,6 +351,19 @@ describe("Session.create", () => {
351351
}),
352352
)
353353

354+
it.effect("stores a trailing-slash directory in the same session list", () =>
355+
Effect.gen(function* () {
356+
const session = yield* Session.Service
357+
358+
const created = yield* session.create({ location: { directory: AbsolutePath.make("/project/") } })
359+
360+
expect(created.location.directory).toBe(location.directory)
361+
expect((yield* session.list({ directory: location.directory })).data.map((item) => item.id)).toEqual([
362+
created.id,
363+
])
364+
}),
365+
)
366+
354367
it.effect("returns the original session when the ID is retried", () =>
355368
Effect.gen(function* () {
356369
const session = yield* Session.Service

0 commit comments

Comments
 (0)