UNPKG

@openzeppelin/upgrade-safe-transpiler

Version:

Solidity preprocessor used to generate OpenZeppelin Contracts Upgrade Safe.

144 lines 5.71 kB
"use strict"; 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