diff --git a/examples/testing-suite/package.json b/examples/testing-suite/package.json index 089e7587..a87691f4 100644 --- a/examples/testing-suite/package.json +++ b/examples/testing-suite/package.json @@ -27,14 +27,14 @@ "dependencies": { "@bitauth/libauth": "^3.1.0-next.2", "cashc": "^0.11.0", - "cashscript": "^0.11.0", - "url-join": "^5.0.0" + "cashscript": "^0.11.0" }, "devDependencies": { "@jest/globals": "^29.7.0", "@types/jest": "^29.5.14", "jest": "^29.7.0", "tsx": "^4.19.2", - "typescript": "^5.7.3" + "typescript": "^5.7.3", + "url-join": "^5.0.0" } } diff --git a/examples/testing-suite/tasks/index.ts b/examples/testing-suite/tasks/index.ts index e04ce9cf..93de020a 100644 --- a/examples/testing-suite/tasks/index.ts +++ b/examples/testing-suite/tasks/index.ts @@ -3,17 +3,58 @@ import fs from 'fs'; import { URL } from 'url'; import urlJoin from 'url-join'; +interface CompilationCacheItem { + mtime: number; +} + export const compile = (): void => { - const directory = new URL('../contracts', import.meta.url); - const result = fs.readdirSync(directory) + const cacheDirectory = new URL('../cache', import.meta.url); + fs.mkdirSync(cacheDirectory, { recursive: true }); + const cacheFile = new URL('../cache/cashc.json', import.meta.url); + let compilationCache: Record = {}; + if (fs.existsSync(cacheFile)) { + compilationCache = JSON.parse(fs.readFileSync(cacheFile, { encoding: 'utf-8' })); + } + + const artifactsDirectory = new URL('../artifacts', import.meta.url); + fs.mkdirSync(artifactsDirectory, { recursive: true }); + + const contractsDirectory = new URL('../contracts', import.meta.url); + const result = fs.readdirSync(contractsDirectory) .filter((fn) => fn.endsWith('.cash')) - .map((fn) => ({ fn, contents: fs.readFileSync(new URL(urlJoin(directory.toString(), fn)), { encoding: 'utf-8' }) })); + .map((fn) => ({ fn, contents: fs.readFileSync(new URL(urlJoin(contractsDirectory.toString(), fn)), { encoding: 'utf-8' }) })); result.forEach(({ fn, contents }) => { - const artifact = compileString(contents); + const mtime = fs.statSync(new URL(urlJoin(contractsDirectory.toString(), fn))).mtimeMs; + if (!compilationCache[fn] || compilationCache[fn].mtime !== mtime) { + console.log(`Compiling ${fn}...`); + const artifact = compileString(contents); - fs.writeFileSync(new URL(`../artifacts/${fn.replace('.cash', '.json')}`, import.meta.url), JSON.stringify(artifact, null, 2)); + exportArtifact(artifact, new URL(`../artifacts/${fn.replace('.cash', '.artifact.ts')}`, import.meta.url)); + compilationCache[fn] = { mtime }; + } }); + + // Write the updated cache back to the file + fs.writeFileSync(cacheFile, JSON.stringify(compilationCache, null, 2), { encoding: 'utf-8' }); +}; + +export const exportArtifact = (obj: object, outPath: string | URL): void => { + const toTs = (value: any): string => { + // First, stringify the object with indentation + let json = JSON.stringify(value, null, 2); + + // Remove quotes from object keys where valid (simple JS identifiers) + json = json.replace( + /"([a-zA-Z_][a-zA-Z0-9_]*)":/g, + '$1:' + ); + + return json; + }; + + const content = `export default ${toTs(obj)} as const;`; + fs.writeFileSync(outPath, content, { encoding: 'utf-8' }); }; switch (process.argv[2]) {