Skip to content
Merged
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
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
"license": "MIT",
"version": "0.0.5",
"description": "Edgelord Solidity snippets.",
"scripts": {
"powerup": "node scripts/powerup.js",
"rebrand": "node scripts/rebrand.js"
},
"files": [
"src/**/*.sol"
],
Expand Down
11 changes: 11 additions & 0 deletions scripts/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
/* CONFIGS */
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

const LATEST_SOLIDITY_VERSION = "0.8.24";
const SRC_DIR = "src";

module.exports = {
LATEST_SOLIDITY_VERSION,
SRC_DIR,
};
109 changes: 109 additions & 0 deletions scripts/io.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
const fs = require("fs");
const path = require("path");
const { SRC_DIR } = require("./config");
/*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
/* I/O Helpers */
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

/**
* Recursively retrieves a list of Solidity files within a given directory.
*
* @param {string} directory - The root directory to search for Solidity files. Defaults to SRC_DIR.
* @param {string[]} fileList - An optional array to accumulate file paths (used for recursion).
* @returns {string[]} An array of Solidity file paths.
*/
function getSolidityFiles(directory = SRC_DIR, fileList = []) {
const files = fs.readdirSync(directory);

files.forEach((file) => {
const filePath = path.join(directory, file);

if (fs.statSync(filePath).isDirectory()) {
getSolidityFiles(filePath, fileList);
} else if (file.endsWith(".sol")) {
fileList.push(filePath);
}
});
return fileList;
}

/**
* Shows the updates to be applied as a table.
*
* @param {Update[]} updates - An array of update objects containing scope, file paths, pattern, and patch.
*/
async function showUpdates(updates) {
console.log(`${updates.length} update(s) can be automatically applied:`);

// Friendly table heading.
updates = updates.map((update) => ({
"Update type": update.scope,
File: update.file,
"Current value": truncate(update.from),
"Proposed change": truncate(update.to),
}));

// Increasing index so it starts from 1 instead of 0.
updates = updates.reduce((acc, u, i) => {
acc[i + 1] = u;
return acc;
}, {});

console.table(updates);
}

/**
* Prompts the user for confirmation with a yes/no question.
*
* @param {string} prompt - The question to ask the user.
* @returns {Promise<boolean>} A Promise that resolves to true if the user confirms, false otherwise.
*/
async function getUserConfirmation(prompt) {
const rl = require("readline").createInterface({
input: process.stdin,
output: process.stdout,
});

const answer = await new Promise((resolve) => {
rl.question(`${prompt} (y/n): `, resolve);
});
rl.close();
return answer.toLowerCase() === "y";
}

/**
* Applies updates to specified files.
*
* @param {Update[]} updates - An array of update objects containing scope, file paths, pattern, and patch.
*/
function applyUpdates(updates) {
updates.forEach((update) => {
let content = fs.readFileSync(update.file, "utf-8");
// The update query may contain reserved regex characters
// that needs to be escaped to be considered literally.
let inputString = update.from.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
content = content.replace(new RegExp(inputString, "g"), update.to);
fs.writeFileSync(update.file, content, "utf-8");
});
console.log(
`🎉 ${updates.length} update(s) applied.\n👀 Please verify before committing to git.`
);
}
/**
* Adds ellipis to text beyond a defined length.
*
* @param {string} Text the text to truncate.
* @returns {string} The truncated text.
*/
function truncate(text) {
let length = 30;
if (text.length <= length) return text;
return text.substr(0, 30) + "\u2026";
}

module.exports = {
getSolidityFiles,
showUpdates,
getUserConfirmation,
applyUpdates,
};
53 changes: 53 additions & 0 deletions scripts/powerup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const fs = require("fs");
const { LATEST_SOLIDITY_VERSION } = require("./config");
const {
getSolidityFiles,
showUpdates,
getUserConfirmation,
applyUpdates,
} = require("./io");

/**
* Powerup: Updates solidity version to `LATEST_SOLIDITY_VERSION`.
*/
async function powerup() {
const updates = [];

for (let filePath of getSolidityFiles()) {
const oldVersion = getSolidityVersion(filePath);
if (!oldVersion) {
console.log(`Could not determine Solidity version in ${filePath}`);
continue;
}

if (oldVersion != LATEST_SOLIDITY_VERSION) {
updates.push({
scope: "Solidity version",
file: filePath,
from: oldVersion,
to: LATEST_SOLIDITY_VERSION,
});
}
}

if (updates.length > 0) {
showUpdates(updates);
const confirmation = await getUserConfirmation(
"Do you want to upgrade these file(s) to the latest Solidity version?"
);
if (confirmation) applyUpdates(updates);
} else {
console.log(
`🎉 All files are already on the latest Solidity version (${LATEST_SOLIDITY_VERSION})!`
);
}
}

function getSolidityVersion(filePath) {
const content = fs.readFileSync(filePath, "utf-8");
const versionMatch = content.match(/pragma solidity (\^)?(\d+\.\d+\.\d+);/);

return versionMatch ? versionMatch[2] : null;
}

powerup();
63 changes: 63 additions & 0 deletions scripts/rebrand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const fs = require("fs");
const {
getSolidityFiles,
showUpdates,
getUserConfirmation,
applyUpdates,
} = require("./io");

/**
* Rebrand: Migrate branding from solady to soledge.
* Currently, only comments are being rebranded.
*/
async function rebrand() {
const updates = [];
const COMMENT_MAPPING = [
{
from: "/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/",
to: "/*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/",
},
{
from: "/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/",
to: "/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/",
},
];

for (let filePath of getSolidityFiles()) {
for (let patch of COMMENT_MAPPING) {
if (fileContainsPattern(filePath, patch.from)) {
updates.push({
scope: "soledge branding",
file: filePath,
from: patch.from,
to: patch.to,
});
}
}
}

if (updates.length > 0) {
showUpdates(updates);
const confirmation = await getUserConfirmation(
"Confirm applying the proposed branding updates?"
);
if (confirmation) applyUpdates(updates);
} else {
console.log(`🎉 All files already adheres to soledge branding guidelines.`);
}
}

function fileContainsPattern(filePath, pattern) {
const content = fs.readFileSync(filePath, "utf-8");

// Escape regex special characters from pattern
pattern = pattern.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");

// Use the escaped pattern in the regex match
const regex = new RegExp(pattern);

// Check if the content matches the pattern
return regex.test(content);
}

rebrand();