Fix file path parsing to allow cross-platform compatibility (#20680)

This commit is contained in:
Jean-Sébastien Herbaux 2024-07-08 11:50:15 +02:00 committed by GitHub
parent 5cd0e23bf5
commit a5a7edb16a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 48 additions and 12 deletions

View File

@ -25,4 +25,21 @@ describe('filePathToPropPath', () => {
expect(filePathToPropPath('./config/test.js', false)).toEqual(['config']);
expect(filePathToPropPath('./config/test.key.js', false)).toEqual(['config', 'test']);
});
describe('Separators', () => {
test('Win32 Separators', () => {
expect(filePathToPropPath('config\\test.js')).toEqual(['config', 'test']);
expect(filePathToPropPath('.\\config\\test.js')).toEqual(['config', 'test']);
});
test('Posix Separators', () => {
expect(filePathToPropPath('config/test.js')).toEqual(['config', 'test']);
expect(filePathToPropPath('./config/test.js')).toEqual(['config', 'test']);
});
test('Mixed Separators (win32 + posix)', () => {
expect(filePathToPropPath('src\\config/test.js')).toEqual(['src', 'config', 'test']);
expect(filePathToPropPath('.\\config/test.js')).toEqual(['config', 'test']);
});
});
});

View File

@ -1,18 +1,37 @@
import _ from 'lodash';
import path from 'node:path';
import fp from 'lodash/fp';
/**
* Returns a path (as an array) from a file path
*/
export const filePathToPropPath = (filePath: string, useFileNameAsKey = true) => {
const cleanPath = filePath.startsWith('./') ? filePath.slice(2) : filePath;
export const filePathToPropPath = (
entryPath: string,
useFileNameAsKey: boolean = true
): string[] => {
const transform = fp.pipe(
// Remove the relative path prefixes: './' for posix (and some win32) and ".\" for win32
removeRelativePrefix,
// Remove the path metadata and extensions
fp.replace(/(\.settings|\.json|\.js)/g, ''),
// Transform to lowercase
// Note: We're using fp.toLower instead of fp.lowercase as the latest removes special characters such as "/"
fp.toLower,
// Split the cleaned path by matching every possible separator (either "/" or "\" depending on the OS)
fp.split(new RegExp(`[\\${path.win32.sep}|${path.posix.sep}]`, 'g')),
// Make sure to remove leading '.' from the different path parts
fp.map(fp.trimCharsStart('.')),
// join + split in case some '.' characters are still present in different parts of the path
fp.join('.'),
fp.split('.'),
// Remove the last portion of the path array if the file name shouldn't be used as a key
useFileNameAsKey ? fp.identity : fp.slice(0, -1)
);
const prop = cleanPath
.replace(/(\.settings|\.json|\.js)/g, '')
.toLowerCase()
.split('/')
.map((p) => _.trimStart(p, '.'))
.join('.')
.split('.');
return useFileNameAsKey === true ? prop : prop.slice(0, -1);
return transform(entryPath) as string[];
};
const removeRelativePrefix = (filePath: string) => {
return filePath.startsWith(`.${path.win32.sep}`) || filePath.startsWith(`.${path.posix.sep}`)
? filePath.slice(2)
: filePath;
};