@@ -5,7 +5,7 @@ jest.mock('platform', () => ({
55 }
66} ) ) ;
77
8- import { getRelativePath , getBasename , getAbsoluteFilePath } from './path' ;
8+ import { getRelativePath , getBasename , getAbsoluteFilePath , getRelativePathWithinBasePath } from './path' ;
99
1010describe ( 'Path Utilities - Windows Platform' , ( ) => {
1111 describe ( 'getRelativePath' , ( ) => {
@@ -25,6 +25,14 @@ describe('Path Utilities - Windows Platform', () => {
2525 expect ( getRelativePath ( 'C:\\Users\\John\\Projects' , 'C:\\Users\\John\\Projects\\src\\components' , false ) ) . toBe ( 'src\\components' ) ;
2626 } ) ;
2727
28+ it ( 'should return ".." for direct parent directory' , ( ) => {
29+ expect ( getRelativePath ( 'C:\\Users\\John\\Projects' , 'C:\\Users\\John' , false ) ) . toBe ( '..' ) ;
30+ } ) ;
31+
32+ it ( 'should return an absolute path for cross-drive targets' , ( ) => {
33+ expect ( getRelativePath ( 'C:\\Users\\John\\Projects' , 'D:\\payload.txt' , false ) ) . toBe ( 'D:\\payload.txt' ) ;
34+ } ) ;
35+
2836 describe ( 'with posixify enabled' , ( ) => {
2937 it ( 'should convert backslashes to forward slashes' , ( ) => {
3038 expect ( getRelativePath ( 'C:\\Users\\John\\Projects' , 'C:\\Users\\John\\Projects\\App' ) ) . toBe ( 'App' ) ;
@@ -181,6 +189,113 @@ describe('Path Utilities - Windows Platform', () => {
181189 } ) ;
182190 } ) ;
183191
192+ describe ( 'getRelativePathWithinBasePath' , ( ) => {
193+ it ( 'should store in-collection files as Windows relative paths with mixed separators' , ( ) => {
194+ const result = getRelativePathWithinBasePath ( 'C:/Users/John/Collections/Api' , 'C:\\Users\\John\\Collections\\Api\\files\\payload.txt' ) ;
195+ expect ( result ) . toBe ( 'files\\payload.txt' ) ;
196+ } ) ;
197+
198+ it ( 'should store nested in-collection files as Windows relative paths' , ( ) => {
199+ const result = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , 'C:\\Users\\John\\Collections\\Api\\folder\\payload.txt' ) ;
200+ expect ( result ) . toBe ( 'folder\\payload.txt' ) ;
201+ } ) ;
202+
203+ it ( 'should handle collection paths with trailing separators' , ( ) => {
204+ const result = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api\\' , 'C:\\Users\\John\\Collections\\Api\\folder\\payload.txt' ) ;
205+ expect ( result ) . toBe ( 'folder\\payload.txt' ) ;
206+ } ) ;
207+
208+ it ( 'should handle case differences in Windows drive paths' , ( ) => {
209+ const result = getRelativePathWithinBasePath ( 'c:\\users\\john\\collections\\api' , 'C:\\Users\\John\\Collections\\Api\\folder\\payload.txt' ) ;
210+ expect ( result ) . toBe ( 'folder\\payload.txt' ) ;
211+ } ) ;
212+
213+ it ( 'should resolve dot segments before deciding whether a file is inside the collection' , ( ) => {
214+ const result = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , 'C:\\Users\\John\\Collections\\Api\\folder\\..\\payload.txt' ) ;
215+ expect ( result ) . toBe ( 'payload.txt' ) ;
216+ } ) ;
217+
218+ it ( 'should keep paths that resolve outside the collection absolute' , ( ) => {
219+ const filePath = 'C:\\Users\\John\\Collections\\Api\\..\\payload.txt' ;
220+ const result = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , filePath ) ;
221+ expect ( result ) . toBe ( filePath ) ;
222+ } ) ;
223+
224+ it ( 'should keep sibling prefix paths absolute' , ( ) => {
225+ const filePath = 'C:\\Users\\John\\Collections\\ApiOther\\payload.txt' ;
226+ const result = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , filePath ) ;
227+ expect ( result ) . toBe ( filePath ) ;
228+ } ) ;
229+
230+ it ( 'should keep outside collection paths absolute' , ( ) => {
231+ const filePath = 'C:\\Users\\John\\Downloads\\payload.txt' ;
232+ const result = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , filePath ) ;
233+ expect ( result ) . toBe ( filePath ) ;
234+ } ) ;
235+
236+ it ( 'should keep cross-drive paths absolute' , ( ) => {
237+ const filePath = 'D:\\payload.txt' ;
238+ const result = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , filePath ) ;
239+ expect ( result ) . toBe ( filePath ) ;
240+ } ) ;
241+
242+ it ( 'should keep same-path values unchanged' , ( ) => {
243+ const filePath = 'C:\\Users\\John\\Collections\\Api' ;
244+ const result = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , filePath ) ;
245+ expect ( result ) . toBe ( filePath ) ;
246+ } ) ;
247+
248+ it ( 'should keep the original file path when inputs are missing' , ( ) => {
249+ expect ( getRelativePathWithinBasePath ( '' , 'C:\\Users\\John\\Downloads\\payload.txt' ) ) . toBe ( 'C:\\Users\\John\\Downloads\\payload.txt' ) ;
250+ expect ( getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , '' ) ) . toBe ( '' ) ;
251+ } ) ;
252+
253+ describe ( 'mixed separators (posix base / win file)' , ( ) => {
254+ it ( 'inside → relative path with native separators (default)' , ( ) => {
255+ const r = getRelativePathWithinBasePath ( 'C:/Users/John/Collections/Api' , 'C:\\Users\\John\\Collections\\Api\\files\\payload.txt' ) ;
256+ expect ( r ) . toBe ( 'files\\payload.txt' ) ;
257+ } ) ;
258+
259+ it ( 'outside → returns original filePath unchanged (default)' , ( ) => {
260+ const r = getRelativePathWithinBasePath ( 'C:/Users/John/Collections/Api' , 'C:\\Users\\John\\Downloads\\payload.txt' ) ;
261+ expect ( r ) . toBe ( 'C:\\Users\\John\\Downloads\\payload.txt' ) ;
262+ } ) ;
263+
264+ it ( 'outside → posixified absolute fallback when posixify=true' , ( ) => {
265+ const r = getRelativePathWithinBasePath ( 'C:/Users/John/Collections/Api' , 'C:\\Users\\John\\Downloads\\payload.txt' , true ) ;
266+ expect ( r ) . toBe ( 'C:/Users/John/Downloads/payload.txt' ) ;
267+ } ) ;
268+
269+ it ( 'inside → posixified relative path when posixify=true' , ( ) => {
270+ const r = getRelativePathWithinBasePath ( 'C:/Users/John/Collections/Api' , 'C:\\Users\\John\\Collections\\Api\\files\\payload.txt' , true ) ;
271+ expect ( r ) . toBe ( 'files/payload.txt' ) ;
272+ } ) ;
273+ } ) ;
274+
275+ describe ( 'mixed separators (win base / posix file)' , ( ) => {
276+ it ( 'inside → relative path with native separators (default)' , ( ) => {
277+ const r = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , 'C:/Users/John/Collections/Api/files/payload.txt' ) ;
278+ expect ( r ) . toBe ( 'files\\payload.txt' ) ;
279+ } ) ;
280+
281+ it ( 'outside → returns original filePath as-is (default)' , ( ) => {
282+ const r = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , 'C:/Users/John/Downloads/payload.txt' ) ;
283+ // filePath uses '/', returned as-is since shouldPosixify=false
284+ expect ( r ) . toBe ( 'C:/Users/John/Downloads/payload.txt' ) ;
285+ } ) ;
286+
287+ it ( 'outside → posixified fallback when posixify=true' , ( ) => {
288+ const r = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , 'C:/Users/John/Downloads/payload.txt' , true ) ;
289+ expect ( r ) . toBe ( 'C:/Users/John/Downloads/payload.txt' ) ;
290+ } ) ;
291+
292+ it ( 'inside → posixified relative path when posixify=true' , ( ) => {
293+ const r = getRelativePathWithinBasePath ( 'C:\\Users\\John\\Collections\\Api' , 'C:/Users/John/Collections/Api/files/payload.txt' , true ) ;
294+ expect ( r ) . toBe ( 'files/payload.txt' ) ;
295+ } ) ;
296+ } ) ;
297+ } ) ;
298+
184299 describe ( 'Cross-platform path handling' , ( ) => {
185300 describe ( 'Windows fromPath with POSIX toPath' , ( ) => {
186301 it ( 'should handle Windows fromPath with POSIX toPath in getAbsoluteFilePath' , ( ) => {
0 commit comments