motoko 1.0.0 → 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +191 -0
- package/contrib/hljs.js +121 -0
- package/contrib/monaco.js +163 -0
- package/index.js +6 -0
- package/interpreter.js +6 -0
- package/lib/__tests__/index.test.js +40 -0
- package/lib/__tests__/interpreter.test.js +15 -0
- package/lib/file.js +66 -0
- package/lib/index.js +120 -0
- package/lib/package.js +163 -0
- package/package.json +47 -10
- package/versions/latest/didc.min.js +1 -0
- package/versions/latest/moc.min.js +1 -0
- package/versions/latest/moc_interpreter.min.js +1 -0
package/lib/index.js
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const { file } = require('./file');
|
4
|
+
const { /* findPackage, */ loadPackages } = require('./package');
|
5
|
+
|
6
|
+
module.exports = (compiler, version) => {
|
7
|
+
const debug = require('debug')(version ? `motoko:${version}` : 'motoko');
|
8
|
+
|
9
|
+
const invoke = (key, unwrap, args) => {
|
10
|
+
if (!compiler) {
|
11
|
+
throw new Error(
|
12
|
+
'Please load a Motoko compiler before running this function',
|
13
|
+
);
|
14
|
+
}
|
15
|
+
if (typeof compiler[key] !== 'function') {
|
16
|
+
throw new Error(`Unknown compiler function: '${key}'`);
|
17
|
+
}
|
18
|
+
let result;
|
19
|
+
try {
|
20
|
+
result = compiler[key](...args);
|
21
|
+
} catch (err) {
|
22
|
+
if (err instanceof Error) {
|
23
|
+
throw err;
|
24
|
+
}
|
25
|
+
throw new Error(
|
26
|
+
`Unable to execute ${key}(${[...args]
|
27
|
+
.map((x) => typeof x)
|
28
|
+
.join(', ')}):\n${JSON.stringify(err)}`,
|
29
|
+
);
|
30
|
+
}
|
31
|
+
if (!unwrap) {
|
32
|
+
return result;
|
33
|
+
}
|
34
|
+
if (!result.code) {
|
35
|
+
throw new Error(
|
36
|
+
result.diagnostics
|
37
|
+
? result.diagnostics
|
38
|
+
.map(({ message }) => message)
|
39
|
+
.join('; ')
|
40
|
+
: '(no diagnostics)',
|
41
|
+
);
|
42
|
+
}
|
43
|
+
return result.code;
|
44
|
+
};
|
45
|
+
|
46
|
+
const mo = {
|
47
|
+
version,
|
48
|
+
compiler,
|
49
|
+
file(path) {
|
50
|
+
return file(mo, path);
|
51
|
+
},
|
52
|
+
// findPackage,
|
53
|
+
async loadPackages(packages) {
|
54
|
+
return loadPackages(mo, packages);
|
55
|
+
},
|
56
|
+
read(path) {
|
57
|
+
return invoke('readFile', false, [path]);
|
58
|
+
},
|
59
|
+
write(path, content = '') {
|
60
|
+
if (typeof content !== 'string') {
|
61
|
+
throw new Error('Non-string file content');
|
62
|
+
}
|
63
|
+
debug('+file', path);
|
64
|
+
invoke('saveFile', false, [path, content]);
|
65
|
+
},
|
66
|
+
rename(path, newPath) {
|
67
|
+
invoke('renameFile', false, [path, newPath]);
|
68
|
+
},
|
69
|
+
delete(path) {
|
70
|
+
debug('-file', path);
|
71
|
+
invoke('removeFile', false, [path]);
|
72
|
+
},
|
73
|
+
list(directory) {
|
74
|
+
return invoke('readDir', false, [directory]);
|
75
|
+
},
|
76
|
+
addPackage(name, directory) {
|
77
|
+
debug('+package', name, directory);
|
78
|
+
invoke('addPackage', false, [name, directory]);
|
79
|
+
},
|
80
|
+
clearPackages() {
|
81
|
+
debug('-packages');
|
82
|
+
invoke('clearPackage', false, []);
|
83
|
+
},
|
84
|
+
setAliases(aliases) {
|
85
|
+
debug('aliases', aliases);
|
86
|
+
invoke('setActorAliases', false, [Object.entries(aliases)]);
|
87
|
+
},
|
88
|
+
setMetadata(values) {
|
89
|
+
invoke('setPublicMetadata', false, [values]);
|
90
|
+
},
|
91
|
+
check(path) {
|
92
|
+
const result = invoke('check', false, [path]);
|
93
|
+
return result.diagnostics;
|
94
|
+
},
|
95
|
+
run(path, libPaths) {
|
96
|
+
return invoke('run', false, [libPaths || [], path]);
|
97
|
+
},
|
98
|
+
candid(path) {
|
99
|
+
return invoke('candid', true, [path]);
|
100
|
+
},
|
101
|
+
wasm(path, mode) {
|
102
|
+
if (!mode) {
|
103
|
+
mode = 'ic';
|
104
|
+
} else if (mode !== 'ic' && mode !== 'wasi') {
|
105
|
+
throw new Error(`Invalid WASM format: ${mode}`);
|
106
|
+
}
|
107
|
+
return invoke('compileWasm', true, [mode, path]);
|
108
|
+
},
|
109
|
+
parseMotoko(content) {
|
110
|
+
const ast = invoke('parseMotoko', true, [content]);
|
111
|
+
return ast;
|
112
|
+
},
|
113
|
+
parseCandid(content) {
|
114
|
+
const ast = invoke('parseCandid', true, [content]);
|
115
|
+
return ast;
|
116
|
+
},
|
117
|
+
};
|
118
|
+
return mo;
|
119
|
+
};
|
120
|
+
exports.default = exports;
|
package/lib/package.js
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
'use strict';
|
2
|
+
// Derived from: https://github.com/dfinity/motoko-playground/blob/main/src/workers/file.ts
|
3
|
+
|
4
|
+
const parse = require('isomorphic-parse-github-url');
|
5
|
+
const fetch = require('cross-fetch');
|
6
|
+
|
7
|
+
async function fetchPackage(mo, info) {
|
8
|
+
if (
|
9
|
+
!info.repo.startsWith('https://github.com/') ||
|
10
|
+
!info.repo.endsWith('.git')
|
11
|
+
) {
|
12
|
+
return false;
|
13
|
+
}
|
14
|
+
const repo = {
|
15
|
+
repo: info.repo.slice(0, -4).replace(/^(https:\/\/github.com\/)/, ''),
|
16
|
+
branch: info.version,
|
17
|
+
dir: info.dir || 'src',
|
18
|
+
};
|
19
|
+
const result = await fetchGithub(mo, repo, info.name);
|
20
|
+
if (result) {
|
21
|
+
mo.addPackage(info.name, info.name + '/');
|
22
|
+
}
|
23
|
+
return result ? true : false;
|
24
|
+
}
|
25
|
+
|
26
|
+
async function fetchGithub(mo, repo, directory = '') {
|
27
|
+
const possiblyCDN = !(
|
28
|
+
(repo.branch.length % 2 === 0 && /^[A-F0-9]+$/i.test(repo.branch)) ||
|
29
|
+
repo.branch === 'master' ||
|
30
|
+
repo.branch === 'main'
|
31
|
+
);
|
32
|
+
if (possiblyCDN) {
|
33
|
+
const result = await fetchFromCDN(repo, directory);
|
34
|
+
if (result) {
|
35
|
+
return result;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
return await fetchFromGithub(mo, repo, directory);
|
39
|
+
}
|
40
|
+
|
41
|
+
// function saveWorkplaceToMotoko(mo, files) {
|
42
|
+
// for (const [name, code] of Object.entries(files)) {
|
43
|
+
// if (!name.endsWith('mo')) continue;
|
44
|
+
// mo.addFile(name, code);
|
45
|
+
// }
|
46
|
+
// }
|
47
|
+
|
48
|
+
async function fetchFromCDN(mo, repo, directory = '') {
|
49
|
+
const meta_url = `https://data.jsdelivr.com/v1/package/gh/${repo.repo}@${repo.branch}/flat`;
|
50
|
+
const base_url = `https://cdn.jsdelivr.net/gh/${repo.repo}@${repo.branch}`;
|
51
|
+
const response = await fetch(meta_url);
|
52
|
+
const json = await response.json();
|
53
|
+
if (!json.hasOwnProperty('files')) {
|
54
|
+
throw new Error(json.message || `Could not fetch from CDN: ${repo}`);
|
55
|
+
}
|
56
|
+
const promises = [];
|
57
|
+
const files = {};
|
58
|
+
for (const f of json.files) {
|
59
|
+
if (f.name.startsWith(`/${repo.dir}/`) && /\.mo$/.test(f.name)) {
|
60
|
+
const promise = (async () => {
|
61
|
+
const content = await (await fetch(base_url + f.name)).text();
|
62
|
+
const stripped =
|
63
|
+
directory +
|
64
|
+
f.name.slice(repo.dir ? repo.dir.length + 1 : 0);
|
65
|
+
mo.write(stripped, content);
|
66
|
+
files[stripped] = content;
|
67
|
+
})();
|
68
|
+
promises.push(promise);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
if (!promises.length) {
|
72
|
+
return;
|
73
|
+
}
|
74
|
+
return Promise.all(promises).then(() => {
|
75
|
+
return files;
|
76
|
+
});
|
77
|
+
}
|
78
|
+
|
79
|
+
async function fetchFromGithub(mo, repo, directory = '') {
|
80
|
+
const meta_url = `https://api.github.com/repos/${repo.repo}/git/trees/${repo.branch}?recursive=1`;
|
81
|
+
const base_url = `https://raw.githubusercontent.com/${repo.repo}/${repo.branch}/`;
|
82
|
+
const response = await fetch(meta_url);
|
83
|
+
const json = await response.json();
|
84
|
+
if (!json.hasOwnProperty('tree')) {
|
85
|
+
throw new Error(
|
86
|
+
json.message || `Could not fetch from GitHub repository: ${repo}`,
|
87
|
+
);
|
88
|
+
}
|
89
|
+
const promises = [];
|
90
|
+
const files = {};
|
91
|
+
for (const f of json.tree) {
|
92
|
+
if (
|
93
|
+
f.path.startsWith(repo.dir ? `${repo.dir}/` : '') &&
|
94
|
+
f.type === 'blob' &&
|
95
|
+
/\.mo$/.test(f.path)
|
96
|
+
) {
|
97
|
+
const promise = (async () => {
|
98
|
+
const content = await (await fetch(base_url + f.path)).text();
|
99
|
+
const stripped =
|
100
|
+
directory +
|
101
|
+
(directory ? '/' : '') +
|
102
|
+
f.path.slice(repo.dir ? repo.dir.length + 1 : 0);
|
103
|
+
mo.write(stripped, content);
|
104
|
+
files[stripped] = content;
|
105
|
+
})();
|
106
|
+
promises.push(promise);
|
107
|
+
}
|
108
|
+
}
|
109
|
+
if (!promises.length) {
|
110
|
+
return;
|
111
|
+
}
|
112
|
+
return Promise.all(promises).then(() => {
|
113
|
+
return files;
|
114
|
+
});
|
115
|
+
}
|
116
|
+
|
117
|
+
// async function resolve(path) {
|
118
|
+
|
119
|
+
// }
|
120
|
+
|
121
|
+
function parseGithubPackage(path, name) {
|
122
|
+
if (!path) {
|
123
|
+
return;
|
124
|
+
}
|
125
|
+
if (typeof path === 'object') {
|
126
|
+
return path;
|
127
|
+
}
|
128
|
+
|
129
|
+
let result;
|
130
|
+
try {
|
131
|
+
result = parse(path);
|
132
|
+
if (!result) {
|
133
|
+
return;
|
134
|
+
}
|
135
|
+
} catch (err) {
|
136
|
+
console.warn(err);
|
137
|
+
}
|
138
|
+
|
139
|
+
const { name: repoName, filepath, branch, owner } = result;
|
140
|
+
|
141
|
+
return {
|
142
|
+
name: name || repoName,
|
143
|
+
repo: `https://github.com/${owner}/${repoName}.git`,
|
144
|
+
version: branch,
|
145
|
+
dir: filepath,
|
146
|
+
// homepage: ,
|
147
|
+
};
|
148
|
+
}
|
149
|
+
|
150
|
+
module.exports = {
|
151
|
+
// async findPackage(package) {
|
152
|
+
// if (typeof package === 'string') {
|
153
|
+
// return resolve(package);
|
154
|
+
// }
|
155
|
+
// return package;
|
156
|
+
// },
|
157
|
+
loadPackages: async (mo, packages) => {
|
158
|
+
for (const [name, path] of Object.entries(packages)) {
|
159
|
+
const info = parseGithubPackage(path, name);
|
160
|
+
return fetchPackage(mo, info);
|
161
|
+
}
|
162
|
+
},
|
163
|
+
};
|
package/package.json
CHANGED
@@ -1,12 +1,49 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
"
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
2
|
+
"name": "motoko",
|
3
|
+
"version": "2.0.3",
|
4
|
+
"description": "Compile Motoko smart contracts in Node.js and the browser.",
|
5
|
+
"author": "Ryan Vandersmith (https://github.com/rvanasa)",
|
6
|
+
"license": "Apache-2.0",
|
7
|
+
"main": "./index.js",
|
8
|
+
"scripts": {
|
9
|
+
"generate": "node utils/generate",
|
10
|
+
"test": "jest"
|
11
|
+
},
|
12
|
+
"dependencies": {
|
13
|
+
"cross-fetch": "3.1.5",
|
14
|
+
"isomorphic-parse-github-url": "1.0.2"
|
15
|
+
},
|
16
|
+
"devDependencies": {
|
17
|
+
"@wasmer/wasi": "^1.0.2",
|
18
|
+
"cross-env": "^7.0.3",
|
19
|
+
"jest": "^28.1.3",
|
20
|
+
"prettier": "^2.7.1"
|
21
|
+
},
|
22
|
+
"directories": {
|
23
|
+
"lib": "lib",
|
24
|
+
"contrib": "contrib"
|
25
|
+
},
|
26
|
+
"files": [
|
27
|
+
"index.js",
|
28
|
+
"interpreter.js",
|
29
|
+
"lib",
|
30
|
+
"contrib",
|
31
|
+
"versions/latest"
|
32
|
+
],
|
33
|
+
"keywords": [
|
34
|
+
"motoko",
|
35
|
+
"language",
|
36
|
+
"programming-language",
|
37
|
+
"dfinity",
|
38
|
+
"smart-contract",
|
39
|
+
"canister",
|
40
|
+
"browser",
|
41
|
+
"ic",
|
42
|
+
"icp",
|
43
|
+
"internet-computer",
|
44
|
+
"blockchain",
|
45
|
+
"cryptocurrency",
|
46
|
+
"nft",
|
47
|
+
"token"
|
48
|
+
]
|
12
49
|
}
|