fix(router-gate): stream A path-normalization — $& replacement, narrow catch, BOM/EOF, docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-05-29 19:48:49 +03:00
parent e0f6c52f37
commit 52e1cfec1a
2 changed files with 44 additions and 7 deletions
+24 -1
View File
@@ -36,6 +36,9 @@ describe('expandEnvVars', () => {
it('$HOMEDIR not matched inside longer name (boundary)', () => {
expect(expandEnvVars('$HOMEDIR', { HOME: '/h' })).toBe('$HOMEDIR');
});
it('val containing $& is inserted literally (no replacement-pattern misinterpretation)', () => {
expect(expandEnvVars('$HOME/test', { HOME: '/a/$&/x' })).toBe('/a/$&/x/test');
});
});
describe('caseFold', () => {
@@ -80,7 +83,7 @@ describe('pathNormalize', () => {
const result = pathNormalize('a/../b', { realpath: (p) => p, resolve: path.posix.resolve, platform: 'linux', homedir: '/h', env: {} });
expect(result.endsWith('/b')).toBe(true);
});
it('falls back to resolved on ENOENT', () => {
it('falls back to resolved on ENOENT (no .code)', () => {
expect(pathNormalize('/missing', {
realpath: () => { throw new Error('ENOENT'); },
resolve: (p) => p,
@@ -89,6 +92,26 @@ describe('pathNormalize', () => {
env: {},
})).toBe('/missing');
});
it('falls back to resolved when error has code ENOENT', () => {
const err = Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
expect(pathNormalize('/missing2', {
realpath: () => { throw err; },
resolve: (p) => p,
platform: 'linux',
homedir: '/h',
env: {},
})).toBe('/missing2');
});
it('rethrows non-ENOENT errors (e.g. EACCES)', () => {
const err = Object.assign(new Error('permission denied'), { code: 'EACCES' });
expect(() => pathNormalize('/denied', {
realpath: () => { throw err; },
resolve: (p) => p,
platform: 'linux',
homedir: '/h',
env: {},
})).toThrow('permission denied');
});
it('case-folds on win32', () => {
expect(pathNormalize('/A/B', { realpath: (p) => p, resolve: (p) => p, platform: 'win32', homedir: '/h', env: {} })).toBe('/a/b');
});