From 1a4c2aa1fd0bb4e31457a160b1c31ca26f3ca4e0 Mon Sep 17 00:00:00 2001 From: Dimitar Bounov Date: Thu, 19 May 2022 20:36:01 -1000 Subject: [PATCH 1/2] Change CompileResult to also include a map from source unit paths to resolved file paths --- src/compile/inference/imports.ts | 16 ++++--- src/compile/utils.ts | 44 +++++++++++++++++-- .../compile/inference/findAllFiles.spec.ts | 8 ++-- 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/compile/inference/imports.ts b/src/compile/inference/imports.ts index 00b07ca5..2a790af3 100644 --- a/src/compile/inference/imports.ts +++ b/src/compile/inference/imports.ts @@ -95,12 +95,13 @@ function computeSourceUnitName( async function resolveSourceUnitName( sourceUnitName: string, resolvers: ImportResolver[] -): Promise { +): Promise<[string, string] | undefined> { for (const resolver of resolvers) { const resolvedPath = resolver.resolve(sourceUnitName); if (resolvedPath !== undefined) { - return fse.readFile(resolvedPath, "utf-8"); + const contents = await fse.readFile(resolvedPath, "utf-8"); + return [contents, resolvedPath]; } } @@ -111,10 +112,12 @@ async function resolveSourceUnitName( * Given a partial map `files` from **source unit names** to file contents, a list of * `remappings` and a list of `ImportResolver`s - `resolvers`, find all * files that are imported from the starting set `files` but are - * **missing** in `files` and add them into the files map. + * **missing** in `files` and add them into the files map. Also for each imported file + * add a mapping from its source unit name to the actual file name in `fileNames`. */ export async function findAllFiles( files: Map, + fileNames: Map, remappings: Remapping[], resolvers: ImportResolver[], visited = new Set() @@ -140,13 +143,16 @@ export async function findAllFiles( // Missing contents - try and fill them in from the resolvers if (content === undefined) { - content = await resolveSourceUnitName(sourceUnitName, resolvers); + const res = await resolveSourceUnitName(sourceUnitName, resolvers); - if (content === undefined) { + if (res === undefined) { throw new CompileInferenceError(`Couldn't find ${sourceUnitName}`); } + content = res[0]; + files.set(sourceUnitName, content); + fileNames.set(sourceUnitName, res[1]); } let flds: AnyFileLevelNode[]; diff --git a/src/compile/utils.ts b/src/compile/utils.ts index 3df69b72..387e9003 100644 --- a/src/compile/utils.ts +++ b/src/compile/utils.ts @@ -26,9 +26,24 @@ export interface MemoryStorage { } export interface CompileResult { + // Raw compiler JSON output data: any; + // Compiler version used compilerVersion?: string; + /** + * Map from file names (either passed in by caller, or source unit names of imported files) + * to the contents of the respective files. + */ files: Map; + /** + * Map from file names appearing in the files map, to the + * actual resolved paths on disk (if any). For compileJSONData this + * map is empty (since nothing was resolved on disk) + */ + resolvedFileNames: Map; + /** + * Map from file-names to the remapping inferred to resolve that given file-name + */ inferredRemappings: Map; } @@ -187,8 +202,9 @@ export async function compileSourceString( const parsedRemapping = parsePathRemapping(remapping); const files = new Map([[fileName, sourceCode]]); + const fileNames = new Map([[fileName, fileName]]); - await findAllFiles(files, parsedRemapping, resolvers); + await findAllFiles(files, fileNames, parsedRemapping, resolvers); const compilerVersionStrategy = getCompilerVersionStrategy([...files.values()], version); const failures: CompileFailure[] = []; @@ -210,6 +226,7 @@ export async function compileSourceString( data, compilerVersion, files, + resolvedFileNames: fileNames, inferredRemappings }; } @@ -257,6 +274,7 @@ export async function compileSol( const parsedRemapping = parsePathRemapping(remapping); const files = new Map(); + const fileNamesMap = new Map(); const visited = new Set(); const isDynamicBasePath = pathOptions.basePath === undefined; @@ -276,8 +294,13 @@ export async function compileSol( } files.set(resolvedFileName, sourceCode); + // We want every key in `files` to also be defined in `fileNamesMap` which is why + // we add this self-mapping + fileNamesMap.set(resolvedFileName, resolvedFileName); + // We want to set the resolved path for every ile passed in by the caller as well + fileNamesMap.set(fileName, resolvedFileName); - await findAllFiles(files, parsedRemapping, resolvers, visited); + await findAllFiles(files, fileNamesMap, parsedRemapping, resolvers, visited); } const compilerVersionStrategy = getCompilerVersionStrategy([...files.values()], version); @@ -300,6 +323,7 @@ export async function compileSol( data, compilerVersion, files, + resolvedFileNames: fileNamesMap, inferredRemappings }; } @@ -336,7 +360,13 @@ export async function compileJsonData( fillFilesFromSources(files, sources); - return { data, compilerVersion, files, inferredRemappings: new Map() }; + return { + data, + compilerVersion, + files, + resolvedFileNames: new Map(), + inferredRemappings: new Map() + }; } if (consistentlyContainsOneOf(sources, "source")) { @@ -360,7 +390,13 @@ export async function compileJsonData( const errors = detectCompileErrors(compileData); if (errors.length === 0) { - return { data: compileData, compilerVersion, files, inferredRemappings: new Map() }; + return { + data: compileData, + compilerVersion, + files, + resolvedFileNames: new Map(), + inferredRemappings: new Map() + }; } failures.push({ compilerVersion, errors }); diff --git a/test/unit/compile/inference/findAllFiles.spec.ts b/test/unit/compile/inference/findAllFiles.spec.ts index 5d7485b1..c5d3f1fb 100644 --- a/test/unit/compile/inference/findAllFiles.spec.ts +++ b/test/unit/compile/inference/findAllFiles.spec.ts @@ -52,7 +52,7 @@ describe("findAllFiles() find all needed imports", () => { const contents = fse.readFileSync(fileName).toString(); const files = new Map([[fileName, contents]]); - await findAllFiles(files, [], [new FileSystemResolver()]); + await findAllFiles(files, new Map(), [], [new FileSystemResolver()]); expect(new Set(files.keys())).toEqual(new Set(expectedAllFiles)); }); @@ -71,7 +71,9 @@ contract Foo { ] ]); - await expect(findAllFiles(files, [], [])).rejects.toThrow(/Failed parsing imports/); + await expect(findAllFiles(files, new Map(), [], [])).rejects.toThrow( + /Failed parsing imports/ + ); }); it("Missing file error", async () => { @@ -85,6 +87,6 @@ contract Foo { ] ]); - await expect(findAllFiles(files, [], [])).rejects.toThrow(/Couldn't find a.sol/); + await expect(findAllFiles(files, new Map(), [], [])).rejects.toThrow(/Couldn't find a.sol/); }); }); From c967d6d175cb0f0e6d07d18b14ba7f48720c371e Mon Sep 17 00:00:00 2001 From: blitz-1306 Date: Mon, 23 May 2022 10:24:14 +0600 Subject: [PATCH 2/2] Few smaller tweaks in naming, comments. Fixed grammar in few places. --- package-lock.json | 2 +- src/compile/inference/imports.ts | 15 +++--- src/compile/utils.ts | 51 ++++++++++++------- .../compile/inference/findAllFiles.spec.ts | 3 +- 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 638b9520..c3ef0b4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "solc-typed-ast", - "version": "9.1.3", + "version": "10.0.0", "license": "Apache-2.0", "dependencies": { "axios": "^0.27.2", diff --git a/src/compile/inference/imports.ts b/src/compile/inference/imports.ts index 2a790af3..22809d8e 100644 --- a/src/compile/inference/imports.ts +++ b/src/compile/inference/imports.ts @@ -101,6 +101,7 @@ async function resolveSourceUnitName( if (resolvedPath !== undefined) { const contents = await fse.readFile(resolvedPath, "utf-8"); + return [contents, resolvedPath]; } } @@ -112,7 +113,7 @@ async function resolveSourceUnitName( * Given a partial map `files` from **source unit names** to file contents, a list of * `remappings` and a list of `ImportResolver`s - `resolvers`, find all * files that are imported from the starting set `files` but are - * **missing** in `files` and add them into the files map. Also for each imported file + * **missing** in `files` and add them into the `files` map. Also for each imported file * add a mapping from its source unit name to the actual file name in `fileNames`. */ export async function findAllFiles( @@ -141,18 +142,20 @@ export async function findAllFiles( let content = files.get(sourceUnitName); - // Missing contents - try and fill them in from the resolvers + /** + * Missing contents - try and fill them in from the resolvers + */ if (content === undefined) { - const res = await resolveSourceUnitName(sourceUnitName, resolvers); + const result = await resolveSourceUnitName(sourceUnitName, resolvers); - if (res === undefined) { + if (result === undefined) { throw new CompileInferenceError(`Couldn't find ${sourceUnitName}`); } - content = res[0]; + content = result[0]; files.set(sourceUnitName, content); - fileNames.set(sourceUnitName, res[1]); + fileNames.set(sourceUnitName, result[1]); } let flds: AnyFileLevelNode[]; diff --git a/src/compile/utils.ts b/src/compile/utils.ts index 387e9003..bd4a0e0b 100644 --- a/src/compile/utils.ts +++ b/src/compile/utils.ts @@ -26,21 +26,30 @@ export interface MemoryStorage { } export interface CompileResult { - // Raw compiler JSON output + /** + * Raw compiler JSON output + */ data: any; - // Compiler version used + + /** + * Compiler version used + */ compilerVersion?: string; + /** - * Map from file names (either passed in by caller, or source unit names of imported files) + * Map from file-names (either passed in by caller, or source unit names of imported files) * to the contents of the respective files. */ files: Map; + /** - * Map from file names appearing in the files map, to the - * actual resolved paths on disk (if any). For compileJSONData this - * map is empty (since nothing was resolved on disk) + * Map from file-names appearing in the `files` map, to the + * actual resolved paths on disk (if any). + * + * For `compileJSONData()` this map is empty (since nothing was resolved on disk). */ resolvedFileNames: Map; + /** * Map from file-names to the remapping inferred to resolve that given file-name */ @@ -63,7 +72,7 @@ export class CompileFailedError extends Error { this.failures = entries; const formattedErrorStr = entries.map( - (entry) => `==== ${entry.compilerVersion} ===:\n ${entry.errors.join("\n")}\n` + (entry) => `==== ${entry.compilerVersion} ====:\n ${entry.errors.join("\n")}\n` ); this.message = `Compiler Errors: ${formattedErrorStr}`; @@ -202,9 +211,9 @@ export async function compileSourceString( const parsedRemapping = parsePathRemapping(remapping); const files = new Map([[fileName, sourceCode]]); - const fileNames = new Map([[fileName, fileName]]); + const resolvedFileNames = new Map([[fileName, fileName]]); - await findAllFiles(files, fileNames, parsedRemapping, resolvers); + await findAllFiles(files, resolvedFileNames, parsedRemapping, resolvers); const compilerVersionStrategy = getCompilerVersionStrategy([...files.values()], version); const failures: CompileFailure[] = []; @@ -226,7 +235,7 @@ export async function compileSourceString( data, compilerVersion, files, - resolvedFileNames: fileNames, + resolvedFileNames, inferredRemappings }; } @@ -274,7 +283,7 @@ export async function compileSol( const parsedRemapping = parsePathRemapping(remapping); const files = new Map(); - const fileNamesMap = new Map(); + const resolvedFileNames = new Map(); const visited = new Set(); const isDynamicBasePath = pathOptions.basePath === undefined; @@ -294,13 +303,19 @@ export async function compileSol( } files.set(resolvedFileName, sourceCode); - // We want every key in `files` to also be defined in `fileNamesMap` which is why - // we add this self-mapping - fileNamesMap.set(resolvedFileName, resolvedFileName); - // We want to set the resolved path for every ile passed in by the caller as well - fileNamesMap.set(fileName, resolvedFileName); - await findAllFiles(files, fileNamesMap, parsedRemapping, resolvers, visited); + /** + * Add self-mapping as we need every key in `files` + * to also be defined in `resolvedFileNames` + */ + resolvedFileNames.set(resolvedFileName, resolvedFileName); + + /** + * Set the resolved path for every file passed in by the caller as well + */ + resolvedFileNames.set(fileName, resolvedFileName); + + await findAllFiles(files, resolvedFileNames, parsedRemapping, resolvers, visited); } const compilerVersionStrategy = getCompilerVersionStrategy([...files.values()], version); @@ -323,7 +338,7 @@ export async function compileSol( data, compilerVersion, files, - resolvedFileNames: fileNamesMap, + resolvedFileNames, inferredRemappings }; } diff --git a/test/unit/compile/inference/findAllFiles.spec.ts b/test/unit/compile/inference/findAllFiles.spec.ts index c5d3f1fb..6b848e4d 100644 --- a/test/unit/compile/inference/findAllFiles.spec.ts +++ b/test/unit/compile/inference/findAllFiles.spec.ts @@ -1,8 +1,7 @@ import expect from "expect"; import fse from "fs-extra"; import { join } from "path"; -import { FileSystemResolver } from "../../../../src"; -import { findAllFiles } from "../../../../src/compile/inference"; +import { FileSystemResolver, findAllFiles } from "../../../../src"; const SAMPLES_DIR = join("test", "samples", "solidity");