Skip to content

Commit 8558a9b

Browse files
committed
fix flatten with remappings
1 parent 04318fc commit 8558a9b

File tree

4 files changed

+87
-74
lines changed

4 files changed

+87
-74
lines changed

apps/remix-ide/ci/makeMockCompiler.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
var fs = require('fs')
44
var compiler = require('solc')
5-
var compilerInput = require('@remix-project/remix-solidity').CompilerInput
5+
var compilerInput = require('@remix-project/remix-solidity').compilerInputFactory
66
var defaultVersion = 'soljson-v0.8.24+commit.e11b9ed9.js'
77
const path = require('path')
88

apps/remix-ide/src/app/plugins/contractFlattener.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react'
22
import {Plugin} from '@remixproject/engine'
33
import {customAction} from '@remixproject/plugin-api'
44
import {concatSourceFiles, getDependencyGraph, normalizeContractPath} from '@remix-ui/solidity-compiler'
5+
import type {CompilerInput, CompilationSource } from '@remix-project/remix-solidity'
56

67
const _paq = (window._paq = window._paq || [])
78

@@ -25,7 +26,7 @@ export class ContractFlattener extends Plugin {
2526
if (data.sources && Object.keys(data.sources).length > 1) {
2627
if (this.triggerFlattenContract) {
2728
this.triggerFlattenContract = false
28-
await this.flattenContract(source, file, data)
29+
await this.flattenContract(source, file, data, JSON.parse(input))
2930
}
3031
}
3132
})
@@ -47,17 +48,17 @@ export class ContractFlattener extends Plugin {
4748
* Takes the flattened result, writes it to a file and returns the result.
4849
* @returns {Promise<string>}
4950
*/
50-
async flattenContract(source: {sources: any; target: string}, filePath: string, data: {contracts: any; sources: any}): Promise<string> {
51+
async flattenContract(source: {sources: any; target: string}, filePath: string, data: {contracts: any; sources: any}, input: CompilerInput): Promise<string> {
5152
const appendage = '_flattened.sol'
5253
const normalized = normalizeContractPath(filePath)
5354
const path = `${normalized[normalized.length - 2]}${appendage}`
54-
const ast = data.sources
55+
const ast: { [contractName: string]: CompilationSource } = data.sources
5556
let dependencyGraph
5657
let sorted
5758
let result
5859
let sources
5960
try {
60-
dependencyGraph = getDependencyGraph(ast, filePath)
61+
dependencyGraph = getDependencyGraph(ast, filePath, input.settings.remappings)
6162
sorted = dependencyGraph.isEmpty() ? [filePath] : dependencyGraph.sort().reverse()
6263
sources = source.sources
6364
result = concatSourceFiles(sorted, sources)

libs/remix-solidity/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export { Compiler } from './compiler/compiler'
22
export { compile } from './compiler/compiler-helpers'
3-
export { default as CompilerInput, getValidLanguage } from './compiler/compiler-input'
3+
export { default as compilerInputFactory, getValidLanguage } from './compiler/compiler-input'
44
export { CompilerAbstract } from './compiler/compiler-abstract'
55
export * from './compiler/types'
66
export { pathToURL, baseURLBin, baseURLWasm, canUseWorker, urlFromVersion } from './compiler/compiler-utils'

libs/remix-ui/solidity-compiler/src/lib/logic/flattenerUtilities.ts

Lines changed: 80 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
import type {CompilationSource, AstNode} from '@remix-project/remix-solidity'
2+
13
const IMPORT_SOLIDITY_REGEX = /^\s*import(\s+).*$/gm;
24
const SPDX_SOLIDITY_REGEX = /^\s*\/\/ SPDX-License-Identifier:.*$/gm;
35

4-
export function getDependencyGraph(ast, target) {
6+
type Visited = { [key: string]: number }
7+
export function getDependencyGraph(ast: { [name: string]: CompilationSource }, target: string, remappings: string[]) {
58
const graph = tsort();
69
const visited = {};
710
visited[target] = 1;
8-
_traverse(graph, visited, ast, target);
11+
_traverse(graph, visited, ast, target, remappings);
912
return graph;
1013
}
1114

@@ -21,32 +24,31 @@ export function concatSourceFiles(files: any[], sources: any) {
2124
return concat;
2225
}
2326

24-
function _traverse(graph, visited, ast, name) {
27+
function _traverse(graph: Graph, visited: Visited, ast: { [name: string]: CompilationSource }, name: string, remappings: string[]) {
2528
let currentAst = null
2629
currentAst = ast[name].ast
2730
const dependencies = _getDependencies(currentAst);
2831
for (const dependency of dependencies) {
29-
const path = resolve(name, dependency);
32+
const path = resolve(name, dependency, remappings);
3033
if (path in visited) {
3134
// continue; // fixes wrong ordering of source in flattened file
3235
}
3336
visited[path] = 1;
3437
graph.add(name, path);
35-
_traverse(graph, visited, ast, path);
38+
_traverse(graph, visited, ast, path, remappings);
3639
}
3740
}
3841

39-
function _getDependencies(ast) {
42+
function _getDependencies(ast: AstNode) {
4043
const dependencies = ast?.nodes
4144
.filter(node => node?.nodeType === 'ImportDirective')
4245
.map(node => node?.file);
4346
return dependencies;
4447
}
4548

46-
4749
// TSORT
4850

49-
function tsort(initial?: any) {
51+
function tsort(initial?: any): Graph {
5052
const graph = new Graph();
5153

5254
if (initial) {
@@ -58,78 +60,88 @@ function tsort(initial?: any) {
5860
return graph;
5961
}
6062

63+
class Graph {
64+
nodes: { [key: string]: any}
65+
constructor() {
66+
this.nodes = {}
67+
}
6168

62-
function Graph() {
63-
this.nodes = {};
64-
}
65-
66-
// Add sorted items to the graph
67-
Graph.prototype.add = function () {
68-
const self = this;
69-
// eslint-disable-next-line prefer-rest-params
70-
let items = [].slice.call(arguments);
71-
72-
if (items.length === 1 && Array.isArray(items[0]))
73-
items = items[0];
74-
75-
items.forEach(function (item) {
76-
if (!self.nodes[item]) {
77-
self.nodes[item] = [];
69+
// Add sorted items to the graph
70+
add (name, path) {
71+
const self = this;
72+
// eslint-disable-next-line prefer-rest-params
73+
let items = [].slice.call(arguments);
74+
75+
if (items.length === 1 && Array.isArray(items[0]))
76+
items = items[0];
77+
78+
items.forEach(function (item) {
79+
if (!self.nodes[item]) {
80+
self.nodes[item] = [];
81+
}
82+
});
83+
84+
for (let i = 1; i < items.length; i++) {
85+
const from = items[i];
86+
const to = items[i - 1];
87+
88+
self.nodes[from].push(to);
7889
}
79-
});
80-
81-
for (let i = 1; i < items.length; i++) {
82-
const from = items[i];
83-
const to = items[i - 1];
84-
85-
self.nodes[from].push(to);
90+
91+
return self;
8692
}
8793

88-
return self;
89-
};
90-
91-
// Depth first search
92-
// As given in http://en.wikipedia.org/wiki/Topological_sorting
93-
Graph.prototype.sort = function () {
94-
const self = this;
95-
const nodes = Object.keys(this.nodes);
96-
97-
const sorted = [];
98-
const marks = {};
99-
100-
for (let i = 0; i < nodes.length; i++) {
101-
const node = nodes[i];
102-
103-
if (!marks[node]) {
104-
visit(node);
94+
// Depth first search
95+
// As given in http://en.wikipedia.org/wiki/Topological_sorting
96+
sort () {
97+
const self = this;
98+
const nodes = Object.keys(this.nodes);
99+
100+
const sorted = [];
101+
const marks = {};
102+
103+
for (let i = 0; i < nodes.length; i++) {
104+
const node = nodes[i];
105+
106+
if (!marks[node]) {
107+
visit(node);
108+
}
109+
}
110+
111+
return sorted;
112+
113+
function visit(node) {
114+
if (marks[node] === 'temp')
115+
throw new Error("There is a cycle in the graph. It is not possible to derive a topological sort.");
116+
else if (marks[node])
117+
return;
118+
119+
marks[node] = 'temp';
120+
self.nodes[node].forEach(visit);
121+
marks[node] = 'perm';
122+
123+
sorted.push(node);
105124
}
106125
}
107126

108-
return sorted;
109-
110-
function visit(node) {
111-
if (marks[node] === 'temp')
112-
throw new Error("There is a cycle in the graph. It is not possible to derive a topological sort.");
113-
else if (marks[node])
114-
return;
115-
116-
marks[node] = 'temp';
117-
self.nodes[node].forEach(visit);
118-
marks[node] = 'perm';
119-
120-
sorted.push(node);
127+
isEmpty () {
128+
const nodes = Object.keys(this.nodes);
129+
return nodes.length === 0;
121130
}
122-
};
123-
124-
Graph.prototype.isEmpty = function () {
125-
const nodes = Object.keys(this.nodes);
126-
return nodes.length === 0;
127131
}
128132

129-
130133
// PATH
131134

132-
function resolve(parentPath, childPath) {
135+
function resolve(parentPath, childPath, remappings: string[]) {
136+
if (remappings && remappings.length) {
137+
for (const mapping of remappings) {
138+
if (mapping.indexOf('=') !== -1) {
139+
const split = mapping.split('=')
140+
childPath = childPath.replace(split[0].trim(), split[1].trim())
141+
}
142+
}
143+
}
144+
133145
if (_isAbsolute(childPath)) {
134146
return childPath;
135147
}

0 commit comments

Comments
 (0)