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.js', false)).toEqual(['config']);
expect(filePathToPropPath('./config/test.key.js', false)).toEqual(['config', 'test']); 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 * Returns a path (as an array) from a file path
*/ */
export const filePathToPropPath = (filePath: string, useFileNameAsKey = true) => { export const filePathToPropPath = (
const cleanPath = filePath.startsWith('./') ? filePath.slice(2) : filePath; 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 return transform(entryPath) as string[];
.replace(/(\.settings|\.json|\.js)/g, '') };
.toLowerCase()
.split('/') const removeRelativePrefix = (filePath: string) => {
.map((p) => _.trimStart(p, '.')) return filePath.startsWith(`.${path.win32.sep}`) || filePath.startsWith(`.${path.posix.sep}`)
.join('.') ? filePath.slice(2)
.split('.'); : filePath;
return useFileNameAsKey === true ? prop : prop.slice(0, -1);
}; };