Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
karneges committed Sep 9, 2023
1 parent 50c2ffb commit e52a2c9
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 43 deletions.
40 changes: 15 additions & 25 deletions sample-project-typescript/locklift.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,21 @@ const config: LockliftConfig = {
version: "0.15.48",
},
networks: {
proxy: {
connection: {
id: 1001,
// @ts-ignore
type: "proxy",
// @ts-ignore
data: {},
},
keys: {
// Use everdev to generate your phrase
// !!! Never commit it in your repos !!!
// phrase: "action inject penalty envelope rabbit element slim tornado dinner pizza off blood",
amount: 20,
},
},
local: {
// Specify connection settings for https://github.com/broxus/everscale-standalone-client/
connection: {
Expand Down Expand Up @@ -71,31 +86,6 @@ const config: LockliftConfig = {
amount: 20,
},
},
test: {
connection: {
id: 1,
type: "graphql",
group: "dev",
data: {
endpoints: [DEV_NET_NETWORK_ENDPOINT],
latencyDetectionInterval: 1000,
local: false,
},
},
giver: {
address: "0:0000000000000000000000000000000000000000000000000000000000000000",
key: "secret key",
},
tracing: {
endpoint: DEV_NET_NETWORK_ENDPOINT,
},
keys: {
// Use everdev to generate your phrase
// !!! Never commit it in your repos !!!
// phrase: "action inject penalty envelope rabbit element slim tornado dinner pizza off blood",
amount: 20,
},
},
venom_testnet: {
connection: {
id: 1000,
Expand Down
145 changes: 145 additions & 0 deletions src/internal/buildCash/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { DirectoryTree } from "directory-tree";
import fs from "fs-extra";
import path from "path";
import { tryToGetNodeModules } from "../cli/builder/utils";
import { tryToGetFileChangeTime } from "./utils";
import { logger } from "../logger";
import chalk from "chalk";
const importMatcher = /^\s*import\s*(?:{[^}]+}\s*from\s*)?["']([^"']+\.tsol)["'];/gm;
const contractMatcher = new RegExp(/^contract [A-Za-z0-9_]+\s+is [A-Za-z0-9_]+\s+\{/gm);
export class BuildCash {
private readonly buildCashFolder = path.join("buildCash", "buildCash.json");
private readonly prevCash: Record<string, { modificationTime: number }>;

constructor(private readonly contracts: DirectoryTree<Record<string, any>>[]) {
fs.ensureFileSync(this.buildCashFolder);
this.prevCash = fs.readJSONSync(this.buildCashFolder, { throws: false }) || [];
}

buildTree() {
const pathToNodeModules = tryToGetNodeModules();
const contractsMap = new Map<string, boolean>();
const contractsWithImports = this.contracts.map(el => {
const contractFile = fs.readFileSync(el.path, {
encoding: "utf-8",
});

if (new RegExp(/^contract [A-Za-z0-9_]+\s+is\s+[A-Za-z0-9_,\s]+\{/gm).test(contractFile)) {
contractsMap.set(el.path, true);
}
const imports = Array.from(contractFile.matchAll(importMatcher))
.map(el => el[1])
.map(imp => {
const localImportPath = path.join(el.path, "..", imp);
const localFileChangeTime = tryToGetFileChangeTime(localImportPath);
if (localFileChangeTime) {
return {
path: localImportPath,
modificationTime: localFileChangeTime,
};
}
const nodeModulesImportPath = path.join(pathToNodeModules!, imp);
const nodeModulesFileChangeTime = tryToGetFileChangeTime(nodeModulesImportPath);
if (nodeModulesFileChangeTime) {
return {
path: nodeModulesImportPath,
modificationTime: nodeModulesFileChangeTime,
};
}
throw new Error(`Can't find import ${imp}`);
});

return { name: el.name, path: el.path, imports };
});
const uniqFiles = new Set<string>();
[
...contractsWithImports.map(el => el.path),
...contractsWithImports.flatMap(el => el.imports.map(el => el.path)),
].forEach(el => uniqFiles.add(el));

const filesWithModTime = Array.from(uniqFiles).reduce((acc, el) => {
return { ...acc, [el]: { modificationTime: fs.statSync(el).mtime.getTime() } };
}, {} as Record<string, { modificationTime: number }>);

fs.writeJSONSync(this.buildCashFolder, filesWithModTime, {
spaces: 4,
});

// if (!this.prevCash) {
// return;
// }

const updatedOrNewFiles = Object.entries(filesWithModTime)
.filter(([filePath, { modificationTime }]) => {
const prevFile = this.prevCash[filePath];
if (!prevFile) {
return true;
}
return prevFile.modificationTime !== modificationTime;
})
.map(([filePath]) => filePath);

const importToFileMap = contractsWithImports.reduce((acc, current) => {
current.imports.forEach(imp => {
acc[imp.path] = acc[imp.path] ? [...acc[imp.path], current.path] : [current.path];
});
return acc;
}, {} as Record<string, string[]>);
const printArr = [] as Array<Print>;
const filesForBuild = findFilesForBuildRecursive(updatedOrNewFiles, importToFileMap, contractsMap, printArr);

recursivePrint(printArr, 3, filesForBuild);
return filesForBuild;
}
}
type Print = { filePath: string; subDep: Array<Print> };
const recursivePrint = (printArr: Array<Print>, level = 0, selectedContracts: Array<string>) => {
printArr.forEach(el => {
console.log(
`${" ".repeat(level)}${selectedContracts.includes(el.filePath) ? chalk.blueBright(el.filePath) : el.filePath}`,
);
recursivePrint(el.subDep, level + 1, selectedContracts);
});
};
const findFilesForBuildRecursive = (
updatedOrNewFiles: string[],
importToFileMap: Record<string, Array<string>>,
contractsMap: Map<string, boolean>,
printArr: Array<Print>,
visitedMap: Map<string, boolean> = new Map(),
): Array<string> => {
return updatedOrNewFiles.reduce((acc, filePath) => {
const importRecords = importToFileMap[filePath];
if (visitedMap.get(filePath)) {
return acc;
}
/// debug
const newPrintArr = [] as Array<Print>;
printArr.push({ filePath, subDep: newPrintArr });
///
if (!importRecords) {
acc.push(filePath);

return acc;
}
// const notVisitedFiles = importRecords.filter(el => !visitedMap.get(el));
const notVisitedFiles = importRecords;

if (notVisitedFiles.length === 0) {
acc.push(filePath);
return acc;
}
if (contractsMap.get(filePath)) {
acc.push(filePath);
}

visitedMap.set(filePath, true);
console.log(`file ${filePath} was visited, imports: ${notVisitedFiles.join("\n")})}`);

// acc.push(filePath);
return [
...acc,
...findFilesForBuildRecursive(notVisitedFiles, importToFileMap, contractsMap, newPrintArr, visitedMap),
];
}, [] as string[]);
};
9 changes: 9 additions & 0 deletions src/internal/buildCash/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import fs from "fs-extra";

export const tryToGetFileChangeTime = (filePath: string): number | undefined => {
try {
return fs.statSync(filePath).mtime.getTime();
} catch (e) {
return undefined;
}
};
16 changes: 6 additions & 10 deletions src/internal/cli/builder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { promisify } from "util";
import { catchError, concat, defer, filter, from, map, mergeMap, tap, throwError, toArray } from "rxjs";
import { logger } from "../../logger";
import semver from "semver/preload";
import { getContractsTree } from "../../utils";
import { BuildCash } from "../../buildCash";

export type BuilderConfig = {
includesPath?: string;
Expand Down Expand Up @@ -58,7 +60,9 @@ export class Builder {

async buildContracts(): Promise<boolean> {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const contractsTree = this.getContractsTree()!;
const contractsTree = getContractsTree(this.options.contracts)!;
const buildCash = new BuildCash(contractsTree).buildTree();
console.log(buildCash);

try {
logger.printInfo(`Found ${contractsTree.length} sources`);
Expand Down Expand Up @@ -186,7 +190,7 @@ export class Builder {

buildDocs(): boolean {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const contractsTree = this.getContractsTree()!;
const contractsTree = getContractsTree(this.options.contracts)!;

try {
logger.printInfo(`Found ${contractsTree.length} sources`);
Expand Down Expand Up @@ -280,12 +284,4 @@ export class Builder {
return acc;
}, []);
}

private getContractsTree() {
const contractsNestedTree = dirTree(this.options.contracts, {
extensions: /\.(sol|tsol)/,
});

return flatDirTree(contractsNestedTree);
}
}
2 changes: 1 addition & 1 deletion src/internal/cli/commands/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ program
.option("-b, --build <build>", "Path to the build folder", "build")
.option("--disable-include-path", "Disables including node_modules. Use this with old compiler versions", false)
.option("-p, --params [value...]", "Parameters to pass to the script")
.requiredOption("-n, --network <network>", "Network to use, choose from configuration")
.option("-n, --network <network>", "Network to use, choose from configuration", "proxy")
.addOption(
new Option("--config <config>", "Path to the config file")
.default(() => loadConfig("locklift.config.ts"))
Expand Down
2 changes: 1 addition & 1 deletion src/internal/cli/commands/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ program
.option("-c, --contracts <contracts>", "Path to the contracts folder", "contracts")
.option("-b, --build <build>", "Path to the build folder", "build")
.option("--disable-include-path", "Disables including node_modules. Use this with old compiler versions", false)
.requiredOption("-n, --network <network>", "Network to use, choose from configuration")
.option("-n, --network <network>", "Network to use, choose from configuration", "proxy")
.addOption(
new Option("--config <config>", "Path to the config file")
.default(() => loadConfig("locklift.config.ts"))
Expand Down
22 changes: 17 additions & 5 deletions src/internal/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ export type KeysConfig = {
amount: number;
};

export type Networks<T extends ConfigState = ConfigState.EXTERNAL> = Record<"local" | string, NetworkValue<T>>;
export interface NetworkValue<T extends ConfigState = ConfigState.EXTERNAL> {
giver: GiverConfig;
export type Networks<T extends ConfigState = ConfigState.EXTERNAL> = Record<"local" | string, NetworkValue<T>> & {
proxy: NetworkValue<T, "proxy">;
};
export interface NetworkValue<T extends ConfigState = ConfigState.EXTERNAL, P extends string = ""> {
giver: T extends ConfigState.EXTERNAL ? (P extends "proxy" ? GiverConfig | undefined : GiverConfig) : GiverConfig;
keys: T extends ConfigState.EXTERNAL ? KeysConfig : Required<KeysConfig>;
connection: T extends ConfigState.EXTERNAL ? ConnectionProperties : ConnectionData;
providerConfig?: {
Expand Down Expand Up @@ -169,8 +171,9 @@ export function loadConfig(configPath: string): LockliftConfig<ConfigState.INTER
if (validationResult.error) {
throw new Error(validationResult.error.annotate());
}
const config = validationResult.value;
for (const value of Object.values(config.networks)) {
const config = { ...validationResult.value } as unknown as LockliftConfig<ConfigState.INTERNAL>;

for (const [key, value] of Object.entries(config.networks)) {
if (value.keys != null) {
value.keys = {
...value.keys,
Expand All @@ -181,6 +184,15 @@ export function loadConfig(configPath: string): LockliftConfig<ConfigState.INTER
if (typeof value.connection === "string") {
value.connection = getPresetParams(value.connection) || value.connection;
}
if (key === "proxy") {
config.networks[key] = {
...value,
giver: value.giver || {
address: "0:ece57bcc6c530283becbbd8a3b24d3c5987cdddc3c8b7b33be6e4a6312490415",
key: "172af540e43a524763dd53b26a066d472a97c4de37d5498170564510608250c3",
},
};
}
}

return config as unknown as LockliftConfig<ConfigState.INTERNAL>;
Expand Down
10 changes: 10 additions & 0 deletions src/internal/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import dirTree from "directory-tree";
import { flatDirTree } from "../cli/builder/utils";

export const getContractsTree = (pathToContractsFolder: string) => {
const contractsNestedTree = dirTree(pathToContractsFolder, {
extensions: /\.(sol|tsol)/,
});

return flatDirTree(contractsNestedTree);
};
2 changes: 1 addition & 1 deletion tsconfig-base.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "esnext",
"target": "ES2020",
/* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ "module": "commonjs",
/* Specify what module code is generated. */ "moduleResolution": "node",
"allowJs": true,
Expand Down

0 comments on commit e52a2c9

Please sign in to comment.