Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion src/solc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,26 @@ function tidy(_line: string) {
return line;
}

type PathModule = Pick<typeof path, 'relative' | 'sep'>;

/**
* Build the source-map key for an imported Solidity file.
*
* solc's `findImports` callback always receives '/'-separated import paths, so
* the keys we register in the sources map must use '/' as well. `path.relative`
* returns OS-native separators — '/' on POSIX but '\' on Windows — so we
* normalise here. On POSIX this is a no-op; on Windows it converts the '\'
* separators that would otherwise cause "couldn't find the import" failures.
*
* `p` is injectable purely so this can be unit-tested deterministically for both
* `path.posix` and `path.win32` regardless of the host OS.
*/
export const toImportKey = (
topDir: string,
importPath: string,
p: PathModule = path,
): string => p.relative(topDir, importPath).split(p.sep).join('/');

const buildSources = (file: any, options: any) => {
const sources = {};
const contractsFiles = [];
Expand All @@ -60,7 +80,8 @@ const buildSources = (file: any, options: any) => {
relPath,
);

relPath = path.relative(options.topDir, importPath);
// Normalise to '/' so this key matches what solc passes to findImports.
relPath = toImportKey(options.topDir, importPath);

contractsFiles.push([importPath, relPath]);
}
Expand Down
34 changes: 34 additions & 0 deletions test/solc-import-path.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import assert from 'assert';
import path from 'path';
import { toImportKey } from '../built/solc.js';

/**
* Regression tests for import-path resolution in src/solc.ts (buildSources).
*
* solc's `findImports` callback always receives '/'-separated paths, so the keys
* we register in the sources map must use '/' too. `path.relative` returns
* OS-native separators, so `toImportKey` normalises them. The Windows case is
* exercised with `path.win32` explicitly, so it runs identically on a Linux CI
* and FAILS without the `.split(p.sep).join('/')` normalisation.
*/
describe('solc import-path key normalisation', function () {
const importPathPosix = '/home/dev/contracts/Escrow-imports/IERC20.sol';
const topDirPosix = '/home/dev/contracts';

const importPathWin = 'C:\\Users\\dev\\contracts\\Escrow-imports\\IERC20.sol';
const topDirWin = 'C:\\Users\\dev\\contracts';

const expected = 'Escrow-imports/IERC20.sol';

it('Linux/POSIX: yields a forward-slash import key', function () {
const key = toImportKey(topDirPosix, importPathPosix, path.posix);
assert.strictEqual(key, expected);
});

it('Windows: yields a forward-slash import key (fails without the fix)', function () {
// Without normalisation this would be 'Escrow-imports\\IERC20.sol', which
// never matches solc's '/'-separated key -> "couldn't find the import".
const key = toImportKey(topDirWin, importPathWin, path.win32);
assert.strictEqual(key, expected);
});
});