diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..8ffcc92 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +src/tolkfiftlib.js +**/*.md diff --git a/jest.config.js b/jest.config.js index f5d30d1..740c620 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,7 @@ /** @type {import('ts-jest').JestConfigWithTsJest} **/ module.exports = { - testEnvironment: "node", + testEnvironment: 'node', transform: { - "^.+.tsx?$": ["ts-jest",{}], + '^.+.tsx?$': ['ts-jest', {}], }, -}; \ No newline at end of file +} diff --git a/package.json b/package.json index 87dd1e4..3d68987 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ "stdlib:pack": "node scripts/pack-stdlib-to-object.js", "wasm:dist": "cp src/tolkfiftlib.js dist && cp src/tolkfiftlib.wasm.js dist", "stdlib:dist": "cp -r src/tolk-stdlib dist && cp src/stdlib.tolk.js dist", - "test": "yarn wasm:pack && yarn stdlib:pack && yarn jest" + "test": "yarn wasm:pack && yarn stdlib:pack && yarn jest", + "fmt": "prettier --write -l --cache .", + "fmt:check": "prettier --check --cache ." }, "author": "TON Blockchain", "license": "MIT", @@ -27,9 +29,31 @@ "@types/jest": "^29.5.12", "jest": "^29.7.0", "ts-jest": "^29.2.4", - "typescript": "^5.5.4" + "typescript": "^5.5.4", + "prettier": "^3.6.2" }, "dependencies": { "arg": "^5.0.2" + }, + "prettier": { + "arrowParens": "avoid", + "bracketSpacing": false, + "printWidth": 100, + "semi": false, + "tabWidth": 2, + "trailingComma": "all", + "useTabs": false, + "singleQuote": true, + "overrides": [ + { + "files": [ + "*.yaml", + "*.yml" + ], + "options": { + "tabWidth": 2 + } + } + ] } } diff --git a/scripts/pack-stdlib-to-object.js b/scripts/pack-stdlib-to-object.js index bf2018b..8d424a3 100644 --- a/scripts/pack-stdlib-to-object.js +++ b/scripts/pack-stdlib-to-object.js @@ -4,7 +4,10 @@ let out = `// stdlib files are stored as strings in order to make it work on web module.exports = {\n\n` let fileNames = [ - ...fs.readdirSync('./src/tolk-stdlib').filter(s => s.endsWith('.tolk')).sort(), + ...fs + .readdirSync('./src/tolk-stdlib') + .filter(s => s.endsWith('.tolk')) + .sort(), ] for (let fileName of fileNames) { @@ -12,7 +15,7 @@ for (let fileName of fileNames) { out += `'@stdlib/${fileName}':\`${contents.replace(/`/g, '\\`')}\`,\n\n` } -out += "};\n" +out += '};\n' fs.writeFileSync('./src/stdlib.tolk.js', out) // note, that Asm.fif and similar are embedded into wasm binary, diff --git a/src/cli.ts b/src/cli.ts index 6e89a97..7059781 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -47,7 +47,7 @@ Options: } if (args._.length !== 1) { - throw 'entrypointFileName wasn\'t specified. Run with -h to see help.' + throw "entrypointFileName wasn't specified. Run with -h to see help." } console.log(`Compiling using Tolk v${version}`) @@ -64,14 +64,21 @@ Options: } if (args['--output-json']) { - fs.writeFileSync(args['--output-json'], JSON.stringify({ - artifactVersion: 1, - tolkVersion: version, - fiftCode: result.fiftCode, - codeBoc64: result.codeBoc64, - codeHashHex: result.codeHashHex, - sourcesSnapshot: result.sourcesSnapshot, - }, null, 2)) + fs.writeFileSync( + args['--output-json'], + JSON.stringify( + { + artifactVersion: 1, + tolkVersion: version, + fiftCode: result.fiftCode, + codeBoc64: result.codeBoc64, + codeHashHex: result.codeHashHex, + sourcesSnapshot: result.sourcesSnapshot, + }, + null, + 2, + ), + ) } if (args['--output-fift']) { diff --git a/src/index.ts b/src/index.ts index 2f05180..ccc482c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,10 @@ // @ts-ignore -import wasmModule from "./tolkfiftlib.js" +import wasmModule from './tolkfiftlib.js' // @ts-ignore -import wasmBase64 from "./tolkfiftlib.wasm.js" +import wasmBase64 from './tolkfiftlib.wasm.js' // @ts-ignore -import stdlibContents from "./stdlib.tolk.js" -import {realpath} from "./path-utils" +import stdlibContents from './stdlib.tolk.js' +import {realpath} from './path-utils' let wasmBinary: Uint8Array | undefined = undefined @@ -22,16 +22,16 @@ export type TolkCompilerConfig = { } export type TolkResultSuccess = { - status: "ok" + status: 'ok' fiftCode: string codeBoc64: string codeHashHex: string stderr: string - sourcesSnapshot: { filename: string, contents: string }[] + sourcesSnapshot: {filename: string; contents: string}[] } export type TolkResultError = { - status: "error" + status: 'error' message: string } @@ -54,10 +54,12 @@ function copyFromCString(mod: WasmModule, inPtr: any): string { async function instantiateWasmModule() { if (wasmBinary === undefined) { - if (typeof Buffer !== 'undefined') { // node.js + if (typeof Buffer !== 'undefined') { + // node.js wasmBinary = new Uint8Array(Buffer.from(wasmBase64, 'base64')) - } else if (typeof window !== 'undefined') { // browser - const binaryString = atob(wasmBase64) // window.atob() is fast and safe for valid base64 strings + } else if (typeof window !== 'undefined') { + // browser + const binaryString = atob(wasmBase64) // window.atob() is fast and safe for valid base64 strings wasmBinary = new Uint8Array(binaryString.length) for (let i = 0; i < binaryString.length; i++) { wasmBinary[i] = binaryString.charCodeAt(i) @@ -77,33 +79,41 @@ export async function getTolkCompilerVersion(): Promise { return result.tolkVersion } -export async function runTolkCompiler(compilerConfig: TolkCompilerConfig): Promise { +export async function runTolkCompiler( + compilerConfig: TolkCompilerConfig, +): Promise { const mod = await instantiateWasmModule() const allocatedPointers = [] const sourcesSnapshot: TolkResultSuccess['sourcesSnapshot'] = [] // see tolk-wasm.cpp: typedef void (*WasmFsReadCallback)(int, char const*, char**, char**) - const callbackPtr = mod.addFunction(function (kind: number, dataPtr: any, destContents: any, destError: any) { - switch (kind) { // enum ReadCallback::Kind in C++ - case 0: // realpath - let relativeFilename = copyFromCString(mod, dataPtr) // from `import` statement, relative to cur file + const callbackPtr = mod.addFunction(function ( + kind: number, + dataPtr: any, + destContents: any, + destError: any, + ) { + // enum ReadCallback::Kind in C++ + switch (kind) { + case 0: // realpath + let relativeFilename = copyFromCString(mod, dataPtr) // from `import` statement, relative to cur file if (!relativeFilename.endsWith('.tolk')) { relativeFilename += '.tolk' } allocatedPointers.push(copyToCStringPtr(mod, realpath(relativeFilename), destContents)) break - case 1: // read file + case 1: // read file try { const filename = copyFromCString(mod, dataPtr) // already normalized (as returned above) if (filename.startsWith('@stdlib/')) { if (filename in stdlibContents) { allocatedPointers.push(copyToCStringPtr(mod, stdlibContents[filename], destContents)) } else { - allocatedPointers.push(copyToCStringPtr(mod, filename + " not found", destError)) + allocatedPointers.push(copyToCStringPtr(mod, filename + ' not found', destError)) } } else { const contents = compilerConfig.fsReadCallback(filename) - sourcesSnapshot.push({ filename, contents }) + sourcesSnapshot.push({filename, contents}) allocatedPointers.push(copyToCStringPtr(mod, contents, destContents)) } } catch (err: any) { @@ -116,7 +126,8 @@ export async function runTolkCompiler(compilerConfig: TolkCompilerConfig): Promi } }, 'viiii') - const configStr = JSON.stringify({ // undefined fields won't be present, defaults will be used, see tolk-wasm.cpp + // undefined fields won't be present, defaults will be used, see tolk-wasm.cpp + const configStr = JSON.stringify({ entrypointFileName: compilerConfig.entrypointFileName, optimizationLevel: compilerConfig.optimizationLevel, withStackComments: compilerConfig.withStackComments, diff --git a/src/path-utils.ts b/src/path-utils.ts index 8c99f7f..2e2fa92 100644 --- a/src/path-utils.ts +++ b/src/path-utils.ts @@ -87,7 +87,8 @@ export function realpath(p: string): string { let isAbsolute = p.charCodeAt(0) === SLASH let path = posixNormalize(p, !isAbsolute) - if (isAbsolute) { // posixNormalize() drops leading slash + if (isAbsolute) { + // posixNormalize() drops leading slash return '/' + path } return path.length === 0 ? '.' : path diff --git a/tests/codegen-checks.spec.ts b/tests/codegen-checks.spec.ts index 1e18ab1..c26b8bc 100644 --- a/tests/codegen-checks.spec.ts +++ b/tests/codegen-checks.spec.ts @@ -1,40 +1,38 @@ -import {runTolkCompiler, getTolkCompilerVersion, TolkResultSuccess, TolkResultError} from "../src"; -import fs from "fs"; +import {runTolkCompiler, getTolkCompilerVersion, TolkResultSuccess, TolkResultError} from '../src' +import fs from 'fs' const EXPECT_TO_CONTAIN = [ -` + ` check1() PROC:<{ NEWC ENDC CTOS HASHSU }> -` +`, ] -const EXPECT_NOT_TO_CONTAIN = [ - 'HASHBU', -] +const EXPECT_NOT_TO_CONTAIN = ['HASHBU'] describe('codegen-checks', () => { - let outFiftCode = '' + let outFiftCode = '' + + beforeAll(async () => { + let result = (await runTolkCompiler({ + entrypointFileName: 'codegen-checks.tolk', + fsReadCallback: path => fs.readFileSync(`./tests/contracts/${path}`, 'utf-8'), + })) as TolkResultSuccess - beforeAll(async () => { - let result = await runTolkCompiler({ - entrypointFileName: "codegen-checks.tolk", - fsReadCallback: path => fs.readFileSync(`./tests/contracts/${path}`, 'utf-8') - }) as TolkResultSuccess + expect(result.status).toEqual('ok') + outFiftCode = result.fiftCode + }) - expect(result.status).toEqual('ok') - outFiftCode = result.fiftCode - }) - - it('check contains', () => { - for (let subFift of EXPECT_TO_CONTAIN) { - expect(outFiftCode).toContain(subFift.trim()) - } - for (let subFift of EXPECT_NOT_TO_CONTAIN) { - expect(outFiftCode).not.toContain(subFift) - } - }) + it('check contains', () => { + for (let subFift of EXPECT_TO_CONTAIN) { + expect(outFiftCode).toContain(subFift.trim()) + } + for (let subFift of EXPECT_NOT_TO_CONTAIN) { + expect(outFiftCode).not.toContain(subFift) + } + }) }) diff --git a/tests/realpath.spec.ts b/tests/realpath.spec.ts index 243c11a..82d40fa 100644 --- a/tests/realpath.spec.ts +++ b/tests/realpath.spec.ts @@ -1,4 +1,4 @@ -import {realpath} from "../src/path-utils"; +import {realpath} from '../src/path-utils' describe('realpath', () => { it('should not change already normalized', () => { diff --git a/tests/tolk-js.spec.ts b/tests/tolk-js.spec.ts index 443524f..e9fcaef 100644 --- a/tests/tolk-js.spec.ts +++ b/tests/tolk-js.spec.ts @@ -1,9 +1,9 @@ -import {runTolkCompiler, getTolkCompilerVersion, TolkResultSuccess, TolkResultError} from "../src"; -import fs from "fs"; -import {Cell} from "@ton/core"; +import {runTolkCompiler, getTolkCompilerVersion, TolkResultSuccess, TolkResultError} from '../src' +import fs from 'fs' +import {Cell} from '@ton/core' describe('tolk-js', () => { - const walletCodeCellHash = "hA3nAz+xEJePYGrDyjJ+BXBcxSp9Y2xaAFLRgGntfDs=" + const walletCodeCellHash = 'hA3nAz+xEJePYGrDyjJ+BXBcxSp9Y2xaAFLRgGntfDs=' it('npm package version should match Tolk version', async () => { let tolkVersion = await getTolkCompilerVersion() @@ -12,13 +12,13 @@ describe('tolk-js', () => { }) it('should compile wallet', async () => { - let result = await runTolkCompiler({ - entrypointFileName: "wallet-code.tolk", - fsReadCallback: path => fs.readFileSync(`./tests/contracts/${path}`, 'utf-8') - }) as TolkResultSuccess + let result = (await runTolkCompiler({ + entrypointFileName: 'wallet-code.tolk', + fsReadCallback: path => fs.readFileSync(`./tests/contracts/${path}`, 'utf-8'), + })) as TolkResultSuccess expect(result.status).toEqual('ok') - let codeCell = Cell.fromBoc(Buffer.from(result.codeBoc64, "base64"))[0] + let codeCell = Cell.fromBoc(Buffer.from(result.codeBoc64, 'base64'))[0] expect(codeCell.hash().toString('base64')).toBe(walletCodeCellHash) }) @@ -28,23 +28,25 @@ describe('tolk-js', () => { tolk 0.1 fun main() { return; } ` - let result = await runTolkCompiler({ - entrypointFileName: "main.tolk", + let result = (await runTolkCompiler({ + entrypointFileName: 'main.tolk', fsReadCallback: _ => source, - }) as TolkResultSuccess + })) as TolkResultSuccess expect(result.status).toEqual('ok') - expect(result.stderr).toContain(`the contract is written in Tolk v0.1, but you use Tolk compiler v${tolkVersion}`) + expect(result.stderr).toContain( + `the contract is written in Tolk v0.1, but you use Tolk compiler v${tolkVersion}`, + ) }) it('should fail if fsReadCallback throws', async () => { - let result = await runTolkCompiler({ - entrypointFileName: "main.tolk", - fsReadCallback: function(path) { + let result = (await runTolkCompiler({ + entrypointFileName: 'main.tolk', + fsReadCallback: function (path) { if (path === 'main.tolk') return 'import "non-existing.tolk";' throw `Can't resolve ${path}` - } - }) as TolkResultError + }, + })) as TolkResultError expect(result.status).toEqual('error') expect(result.message).toContain("Can\'t resolve non-existing.tolk") @@ -53,10 +55,10 @@ describe('tolk-js', () => { it('should normalize import paths', async () => { let res = await runTolkCompiler({ entrypointFileName: 'main.tolk', - fsReadCallback: function(path) { - if (path === 'main.tolk') return `import "../lib.tolk"; import "some/../near.tolk"; import "/var/./cold.tolk"; fun main() {}` - if (path === '../lib.tolk' || path === 'near.tolk' || path === '/var/cold.tolk') - return `` + fsReadCallback: function (path) { + if (path === 'main.tolk') + return `import "../lib.tolk"; import "some/../near.tolk"; import "/var/./cold.tolk"; fun main() {}` + if (path === '../lib.tolk' || path === 'near.tolk' || path === '/var/cold.tolk') return `` throw "can't resolve path " + path }, }) @@ -65,36 +67,36 @@ describe('tolk-js', () => { }) it('should return sourcesSnapshot', async () => { - let result = await runTolkCompiler({ - entrypointFileName: "wallet-code.tolk", - fsReadCallback: path => fs.readFileSync(`./tests/contracts/${path}`, 'utf-8') - }) as TolkResultSuccess + let result = (await runTolkCompiler({ + entrypointFileName: 'wallet-code.tolk', + fsReadCallback: path => fs.readFileSync(`./tests/contracts/${path}`, 'utf-8'), + })) as TolkResultSuccess expect(result.sourcesSnapshot.map(s => s.filename)).toStrictEqual([ - 'wallet-code.tolk', - '../imports/wallet-helpers.tolk', - '../imports/wallet-storage.tolk', - '../imports/wallet-nothing.tolk', - ]); + 'wallet-code.tolk', + '../imports/wallet-helpers.tolk', + '../imports/wallet-storage.tolk', + '../imports/wallet-nothing.tolk', + ]) }) it('should import @stdlib/ files', async () => { - let result = await runTolkCompiler({ - entrypointFileName: "use-dicts.tolk", - fsReadCallback: path => fs.readFileSync(`./tests/contracts/${path}`, 'utf-8') - }) as TolkResultSuccess + let result = (await runTolkCompiler({ + entrypointFileName: 'use-dicts.tolk', + fsReadCallback: path => fs.readFileSync(`./tests/contracts/${path}`, 'utf-8'), + })) as TolkResultSuccess expect(result.status).toEqual('ok') expect(result.fiftCode).toContain('prepareDict_3_30_4_40_5_x') }) it('should fail if import @stdlib/ unexisting', async () => { - let result = await runTolkCompiler({ - entrypointFileName: "main.tolk", - fsReadCallback: _ => 'import "@stdlib/nonexisting"' - }) as TolkResultError + let result = (await runTolkCompiler({ + entrypointFileName: 'main.tolk', + fsReadCallback: _ => 'import "@stdlib/nonexisting"', + })) as TolkResultError expect(result.status).toEqual('error') - expect(result.message).toContain("@stdlib/nonexisting.tolk not found") + expect(result.message).toContain('@stdlib/nonexisting.tolk not found') }) }) diff --git a/tsconfig.json b/tsconfig.json index 26feb07..13da0fe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,9 +7,7 @@ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, - "skipLibCheck": true, + "skipLibCheck": true }, - "include": [ - "src/**/*" - ] -} \ No newline at end of file + "include": ["src/**/*"] +} diff --git a/yarn.lock b/yarn.lock index d8316e3..dc7ec28 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1893,6 +1893,11 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +prettier@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393" + integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== + pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"