@openzeppelin/upgrade-safe-transpiler
Version:
Solidity preprocessor used to generate OpenZeppelin Contracts Upgrade Safe.
144 lines • 5.71 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Transform = void 0;
const lodash_1 = require("lodash");
const src_decoder_1 = require("./solc/src-decoder");
const layout_getter_1 = require("./solc/layout-getter");
const shifts_1 = require("./shifts");
const apply_1 = require("./transformations/apply");
const compare_1 = require("./transformations/compare");
const ast_resolver_1 = require("./ast-resolver");
const match_1 = require("./utils/match");
class Transform {
state = {};
data = new WeakMap();
decodeSrc;
getLayout;
resolver;
constructor(input, output, options = {}) {
this.decodeSrc = (0, src_decoder_1.srcDecoder)(output);
this.getLayout = (0, layout_getter_1.layoutGetter)(output);
this.resolver = new ast_resolver_1.ASTResolver(output, options.exclude);
for (const source in input.sources) {
if (options.exclude?.(source)) {
continue;
}
const s = input.sources[source];
if (!('content' in s)) {
throw new Error(`Missing content for ${source}`);
}
const contentBuf = Buffer.from(s.content);
this.state[source] = {
id: output.sources[source].id,
ast: output.sources[source].ast,
original: s.content,
originalBuf: contentBuf,
content: contentBuf,
transformations: [],
shifts: [],
};
}
}
apply(transform) {
for (const source in this.state) {
const { original: originalSource, originalBuf: originalSourceBuf, ast } = this.state[source];
const { resolver, getLayout } = this;
const readOriginal = this.readOriginal.bind(this);
const getData = this.getData.bind(this);
const error = this.error.bind(this);
const matchOriginalAfter = this.matchOriginalAfter.bind(this);
const tools = {
originalSource,
originalSourceBuf,
resolver,
readOriginal,
getData,
getLayout,
error,
matchOriginalAfter,
};
for (const t of transform(ast, tools)) {
const { id, content, shifts, transformations } = this.state[source];
const error = (byteIndex, msg) => this.error({ src: `${byteIndex}:0:${id}` }, msg);
insertSortedAndValidate(transformations, t, error);
const { result, shift } = (0, apply_1.applyTransformation)(t, content, shifts, this);
shifts.push(shift);
this.state[source].content = result;
}
}
}
getData(node) {
let data = this.data.get(node);
if (data === undefined) {
data = {};
this.data.set(node, data);
}
return data;
}
readOriginal(node, type = 'string') {
const { source, start, length } = this.decodeSrc(node.src);
const { originalBuf } = this.state[source];
const buf = originalBuf.slice(start, start + length);
if (type === 'buffer') {
return buf;
}
else {
return buf.toString('utf8');
}
}
read(node) {
const { source } = this.decodeSrc(node.src);
const { content } = this.state[source];
const sb = this.getShiftedBounds(node);
return content.slice(sb.start, sb.start + sb.length).toString();
}
getShiftedBounds(node) {
const { source, ...bounds } = this.decodeSrc(node.src);
const { shifts, transformations } = this.state[source];
const incompatible = (t) => {
const c = (0, compare_1.compareContainment)(t, bounds);
return c === 'partial overlap' || (typeof c === 'number' && c > 0);
};
if (transformations.some(incompatible)) {
throw new Error(`Can't read from segment that has been partially transformed`);
}
return (0, shifts_1.shiftBounds)(shifts, bounds);
}
error(node, msg) {
const { source, start } = this.decodeSrc(node.src);
const line = byteToLineNumber(this.state[source].originalBuf, start);
const error = new Error(`${msg} (${source}:${line})`);
Error.captureStackTrace(error, this.error); // capture stack trace without this function
return error;
}
matchOriginalAfter(node, re) {
const { source, start, length } = this.decodeSrc(node.src);
const buf = this.state[source].originalBuf;
return (0, match_1.matchBufferAt)(buf, re, start + length);
}
results() {
return (0, lodash_1.mapValues)(this.state, s => s.content.toString());
}
asts() {
return Object.values(this.state).map(s => s.ast);
}
exclude(source) {
delete this.state[source];
}
}
exports.Transform = Transform;
function insertSortedAndValidate(transformations, t, error) {
transformations.push(t);
transformations.sort(compare_1.compareTransformations); // checks for overlaps
for (let i = transformations.indexOf(t) + 1; i < transformations.length; i += 1) {
const s = transformations[i];
const c = (0, compare_1.compareContainment)(t, s);
if (typeof c === 'number' && c < 0) {
throw error(s.start, `A bigger area has already been transformed (${s.kind} > ${t.kind})`);
}
}
}
function byteToLineNumber(buf, byteIndex) {
return buf.slice(0, byteIndex).toString('utf8').split('\n').length;
}
//# sourceMappingURL=transform.js.map