Executing AssemblyScript directly, and compiling to JavaScript with tsc, Deno, and Bun (and executing WASM directly with bun)
bun install typescript@next assemblyscript @types/node
bun add v1.2.1-canary.15 (5633ec43)
installed typescript@5.8.0-dev.20250129 with binaries:
- tsc
- tsserver
installed assemblyscript@0.27.32 with binaries:
- asc
- asinit
installed @types/node@22.12.0
6 packages installed [17.07s]
Install AssemblyScript's WASI shim
bun install assemblyscript/wasi-shim
bun add v1.2.1-canary.15 (5633ec43)
installed @assemblyscript/wasi-shim@github:assemblyscript/wasi-shim#4399cff
1 package installed [1.92s]
The script accepts two integers reflecting the factorial integer to create
an Array
of len
length, and the nth lexicographic permutation n
of the
created Array
. The file is then copied to node_modules/assemblyscript/std
.
We read len
and n
either as stdin
to WASM with WASI support or as arguments
passed to the runtime (JavaScript or WebAssembly).
We import AssemblyScript's std/portable.js
and node:process
, and include
two // @ts-ignore
comments to ignore AssemblyScript's read()
which is not
the same as process.read()
or fs.read()
; and String.UTF8.decode()
, which
will be replaced in the JavaScript transformed/compiled version
import "./portable/index.js";
import process from "node:process";
// array_nth_permutation
// https://stackoverflow.com/a/34238979
export function array_nth_permutation(len: i32, n: i32): void { //Array<f64>
let lex = n; // length of the set
let b: i32[] = []; // copy of the set a.slice()
for (let x: i32 = 0; x < len; x++) {
b.push(x);
}
const res: i32[] = []; // return value, undefined
let i: i32 = 1;
let f: i32 = 1;
// compute f = factorial(len)
for (; i <= len; i++) {
f *= i;
}
let fac = f;
// if the permutation number is within range
if (n >= 0 && n < f) {
// start with the empty set, loop for len elements
// let result_len = 0;
for (; len > 0; len--) {
// determine the next element:
// there are f/len subsets for each possible element,
f /= len;
// a simple division gives the leading element index
i = (n - n % f) / f; // Math.floor(n / f);
// alternately: i = (n - n % f) / f;
// res[(result_len)++] = b[i];
// for (let j = i; j < len; j++) {
// b[j] = b[j + 1]; // shift elements left
// }
res.push(<i32>b.splice(i, 1)[0]);
// reduce n for the remaining subset:
// compute the remainder of the above division
n %= f;
// extract the i-th element from b and push it at the end of res
}
let result: string = `[${res}]`;
process.stdout.write(
`${lex} of ${fac - 1} (0-indexed, factorial ${fac}) => ${result}\n`,
);
process.exit(0);
} else {
if (n === 0) {
process.stdout.write(`${n} = 0`);
}
process.stdout.write(`${n} >= 0 && ${n} < ${f}: ${n >= 0 && n < f}`);
process.exit(1);
}
}
let input: string = "0";
let lex: string = "0";
if (process.argv.length > 1) {
input = process.argv.at(-2);
lex = process.argv.at(-1);
} else {
let stdin = process.stdin;
let buffer = new ArrayBuffer(64);
// @ts-ignore
let n: number = stdin.read(buffer);
if (n > 0) {
// @ts-ignore
let data = String.UTF8.decode(buffer);
input = data.slice(0, data.indexOf(" "));
lex = data.slice(data.indexOf(" "), data.length);
}
}
input = input.trim();
lex = lex.trim();
if (<i32> parseInt(input) < 2 || <i32> parseInt(lex) < 0) {
process.stdout.write(`Expected n > 2, m >= 0, got ${input}, ${lex}`); // eval(input)
process.exit(1);
}
array_nth_permutation(<i32> parseInt(input), <i32> parseInt(lex));
node_modules/.bin/asc --enable simd --exportStart --config \
./node_modules/@assemblyscript/wasi-shim/asconfig.json module.ts -o module.wasm
wasmtime module.wasm 7 8
8 of 5039 (0-indexed, factorial 5040) => [0,1,2,4,5,3,6]
echo '9 9' | wasmer module.wasm
9 of 362879 (0-indexed, factorial 362880) => [0,1,2,3,4,6,7,8,5]
Create a symbolic link to @types/node
in the same node_modules
folder in
assemblyscript/std/types
ln -sf "$PWD/node_modules/@types/node" "$PWD/node_modules/assemblyscript/std/types"
Create tsconfig.json
file
touch tsconfig.json
Edit the file to include
{
"extends": "../tsconfig-base.json",
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"allowJs": true,
"esModuleInterop": true,
"typeRoots": [ "types" ],
"types": [ "portable", "node" ],
"lib": ["esnext", "esnext.string"]
},
"files": ["module.ts"],
"fmt": {
"useTabs": false,
"lineWidth": 80,
"indentWidth": 2
}
}
Copy tsconfig.json
to assemblyscript/std
cp tsconfig.json node_modules/assemblyscript/std
./node_modules/.bin/tsc -p ./node_modules/assemblyscript/std/tsconfig.json
creates module.js
in assemblyscript/std
.
Modify JavaScript emitted by tsc
, deno
, and bun
to change expected arguments
length to >=3
, substitute node:fs
readSync()
for AssemblyScript's read()
,
new Uint8Array(new ArrayBuffer(64))
for ArrayBuffer(64)
, and TextDecoder()
for
String.UTF8.decode()
, and comment import ./portable/index.js
// import"./portable/index.js";
import process from "node:process";
import { readSync } from "node:fs";
export function array_nth_permutation(len, n) {
let lex = n;
let b = [];
for (let x = 0;x < len; x++) {
b.push(x);
}
const res = [];
let i = 1;
let f = 1;
for (;i <= len; i++) {
f *= i;
}
let fac = f;
if (n >= 0 && n < f) {
for (;len > 0; len--) {
f /= len;
i = (n - n % f) / f;
res.push(b.splice(i, 1)[0]);
n %= f;
}
let result = `[${res}]`;
process.stdout.write(`${lex} of ${fac - 1} (0-indexed, factorial ${fac}) => ${result}
`);
process.exit(0);
} else {
if (n === 0) {
process.stdout.write(`${n} = 0`);
}
process.stdout.write(`${n} >= 0 && ${n} < ${f}: ${n >= 0 && n < f}`);
process.exit(1);
}
}
let input = "0";
let lex = "0";
if (process.argv.length >= 3) {
input = process.argv.at(-2);
lex = process.argv.at(-1);
} else {
let stdin = process.stdin;
let buffer = new Uint8Array(new ArrayBuffer(64));
// @ts-ignore
// Use fs.readSync()
let n = readSync(stdin.fd, buffer);
// let n = stdin.read(64);
if (n > 0) {
// @ts-ignore
// let data = String.UTF8.decode(buffer);
// Use TextDecoder
let data = new TextDecoder().decode(buffer);
input = data.slice(0, data.indexOf(" "));
lex = data.slice(data.indexOf(" "), data.length);
}
}
input = input.trim();
lex = lex.trim();
if (parseInt(input) < 2 || parseInt(lex) < 0) {
process.stdout.write(`Expected n > 2, m >= 0, got ${input}, ${lex}`);
process.exit(1);
}
array_nth_permutation(parseInt(input), parseInt(lex));
Run AssemblyScript source code in .ts
file directly with deno
deno -A -q -c node_modules/assemblyscript/std/tsconfig.json ./node_modules/assemblyscript/std/module.ts 12 2
2 of 479001599 (0-indexed, factorial 479001600) => [0,1,2,3,4,5,6,7,8,10,9,11]
deno install -f -c node_modules/assemblyscript/std/tsconfig.json module.ts
Unsupported compiler options in "file:///home/user/node_modules/assemblyscript/std/tsconfig.json".
The following options were ignored:
allowJs, esModuleInterop, module, target, typeRoots
Write the cached file to current working directory
cat "$HOME/.cache/deno/gen/file$PWD/module.ts.js" > module.ts.js
See https://gist.github.com/guest271314/d50e4dd304cf7b3247128e124c619023#modifying-emitted-javascript
deno -A module.ts.js 11 22
22 of 39916799 (0-indexed, factorial 39916800) => [0,1,2,3,4,5,6,10,9,7,8]
bun
runs .wasm
files, see Bun.build
.node
.wasm
These files are supported by the Bun runtime, but during bundling they are treated as assets.
bun module.wasm 4 5
5 of 23 (0-indexed, factorial 24) => [0,3,2,1]
bun run node_modules/assemblyscript/std/module.ts 12 2
2 of 479001599 (0-indexed, factorial 479001600) => [0,1,2,3,4,5,6,7,8,10,9,11]
--no-bundle
removes comments. Omit --no-bundle
option to include portable/index.js
in the bundle
bun build node_modules/assemblyscript/std/module.ts --no-bundle --outfile module.js
module.js 1.39 KB
[10ms] transpile
See Modifying emitted JavaScript
echo '4 5' | bun module.js
5 of 23 (0-indexed, factorial 24) => [0,3,2,1]
Try executing AssemblyScript's .ts
directly with node
node node_modules/assemblyscript/std/module.ts 12 2
node:internal/modules/typescript:170
throw new ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING(filename);
^
Error [ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING]: Stripping types is currently
unsupported for files under node_modules, for "file:///home/user/node_modules/assemblyscript/std/module.ts"
at stripTypeScriptModuleTypes (node:internal/modules/typescript:170:11)
at ModuleLoader.<anonymous> (node:internal/modules/esm/translators:547:16)
at #translate (node:internal/modules/esm/loader:473:12)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:520:27)
at async ModuleJob._link (node:internal/modules/esm/module_job:115:19) {
code: 'ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING'
}
Node.js v24.0.0-nightly20250128532fff6b27
See Modifying emitted JavaScript
node module.ts.js 11 22
22 of 39916799 (0-indexed, factorial 39916800) => [0,1,2,3,4,5,6,10,9,7,8]
@junior-boop @MohsinDev369 @dsir-minute @vemas23 @AlphaFoxz
Re oven-sh/bun#6205 Bun can already execute AssemblyScript source code and
.wasm
files directly. See above.