motoko 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -0
- package/lib/generated/.prettierignore +1 -0
- package/lib/generated/moc.js +288386 -0
- package/lib/index.js +84 -0
- package/lib/index.test.js +17 -0
- package/lib/package.js +156 -0
- package/package.json +42 -0
package/lib/index.js
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
'use strict'
|
2
|
+
|
3
|
+
const debug = require('debug')('motoko');
|
4
|
+
|
5
|
+
const { Motoko } = require('./generated/moc');
|
6
|
+
const { loadPackages } = require('./package');
|
7
|
+
|
8
|
+
const invoke = (key, unwrap, args) => {
|
9
|
+
let result;
|
10
|
+
try {
|
11
|
+
result = Motoko[key](...args);
|
12
|
+
} catch (e) {
|
13
|
+
throw new Error(
|
14
|
+
`Unable to execute ${key}(${[...args]
|
15
|
+
.map((x) => typeof x)
|
16
|
+
.join(', ')}):\n${JSON.stringify(e)}`,
|
17
|
+
);
|
18
|
+
}
|
19
|
+
if (!unwrap) {
|
20
|
+
return result;
|
21
|
+
}
|
22
|
+
if (!result.code) {
|
23
|
+
throw new Error(
|
24
|
+
result.diagnostics
|
25
|
+
? result.diagnostics.map(({ message }) => message).join('; ')
|
26
|
+
: '(no diagnostics)',
|
27
|
+
);
|
28
|
+
}
|
29
|
+
return result.code;
|
30
|
+
};
|
31
|
+
|
32
|
+
// for (const key of Object.keys(Motoko)) {
|
33
|
+
// if (typeof Motoko[key] === 'function') {
|
34
|
+
// const fn = Motoko[key];
|
35
|
+
// Motoko[key] = (...args) => {
|
36
|
+
// debug(key, ...args);
|
37
|
+
// fn(...args);
|
38
|
+
// };
|
39
|
+
// }
|
40
|
+
// }
|
41
|
+
|
42
|
+
module.exports = {
|
43
|
+
Motoko,
|
44
|
+
loadPackages,
|
45
|
+
addFile(path, content) {
|
46
|
+
debug('+file', path);
|
47
|
+
try {
|
48
|
+
// TEMP
|
49
|
+
invoke('saveFile', false, [path, content]);
|
50
|
+
return true;
|
51
|
+
} catch (e) {
|
52
|
+
return false;
|
53
|
+
}
|
54
|
+
},
|
55
|
+
removeFile(path) {
|
56
|
+
debug('-file', path);
|
57
|
+
invoke('removeFile', false, [path, content]);
|
58
|
+
},
|
59
|
+
getFiles(path) {
|
60
|
+
const files = invoke('readDir', false, [path]);
|
61
|
+
|
62
|
+
return files;
|
63
|
+
},
|
64
|
+
addPackage(name, path) {
|
65
|
+
debug('+package', name, path);
|
66
|
+
invoke('addPackage', false, [name, path]);
|
67
|
+
},
|
68
|
+
clearPackages() {
|
69
|
+
debug('-packages');
|
70
|
+
invoke('clearPackage', false, []);
|
71
|
+
},
|
72
|
+
parse(content) {
|
73
|
+
const ast = invoke('parse', true, [content]);
|
74
|
+
return ast;
|
75
|
+
},
|
76
|
+
parseCandid(content) {
|
77
|
+
const ast = invoke('parseCandid', true, [content]);
|
78
|
+
return ast;
|
79
|
+
},
|
80
|
+
candid(path) {
|
81
|
+
return invoke('candid', true, [path]);
|
82
|
+
},
|
83
|
+
};
|
84
|
+
exports.default = exports;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
'use strict'
|
2
|
+
|
3
|
+
const Motoko = require('.');
|
4
|
+
|
5
|
+
const actorMo = `
|
6
|
+
actor Main {
|
7
|
+
public func test() : async Nat {
|
8
|
+
123
|
9
|
+
}
|
10
|
+
}
|
11
|
+
`;
|
12
|
+
|
13
|
+
test('placeholder', () => {
|
14
|
+
expect(true).toEqual(true); // placeholder
|
15
|
+
|
16
|
+
console.log(Motoko.parse(actorMo));
|
17
|
+
});
|
package/lib/package.js
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
'use strict';
|
2
|
+
// Derived from: https://github.com/dfinity/motoko-playground/blob/main/src/workers/file.ts
|
3
|
+
|
4
|
+
const parse = require('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.addFile(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.addFile(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
|
+
function parseGithubPackage(path, name) {
|
118
|
+
if (!path) {
|
119
|
+
return;
|
120
|
+
}
|
121
|
+
if (typeof path === 'object') {
|
122
|
+
return path;
|
123
|
+
}
|
124
|
+
|
125
|
+
let result;
|
126
|
+
try {
|
127
|
+
result = parse(path);
|
128
|
+
if (!result) {
|
129
|
+
return;
|
130
|
+
}
|
131
|
+
} catch (err) {
|
132
|
+
console.warn(err);
|
133
|
+
}
|
134
|
+
|
135
|
+
console.log(result);
|
136
|
+
const { name: repoName, filepath, branch, owner } = result;
|
137
|
+
|
138
|
+
return {
|
139
|
+
name: name || repoName,
|
140
|
+
// repo,
|
141
|
+
repo: `https://github.com/${owner}/${repoName}.git`,
|
142
|
+
version: branch,
|
143
|
+
dir: filepath,
|
144
|
+
// homepage: ,
|
145
|
+
};
|
146
|
+
}
|
147
|
+
|
148
|
+
module.exports = {
|
149
|
+
async loadPackages(packages) {
|
150
|
+
for (const [name, path] of Object.entries(packages)) {
|
151
|
+
const mo = require('.');
|
152
|
+
const info = parseGithubPackage(path, name);
|
153
|
+
return fetchPackage(mo, info);
|
154
|
+
}
|
155
|
+
},
|
156
|
+
};
|
package/package.json
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
{
|
2
|
+
"name": "motoko",
|
3
|
+
"version": "0.1.0",
|
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": "lib/index.js",
|
8
|
+
"scripts": {
|
9
|
+
"test": "jest"
|
10
|
+
},
|
11
|
+
"dependencies": {
|
12
|
+
"cross-fetch": "^3.1.5",
|
13
|
+
"parse-github-url": "^1.0.2"
|
14
|
+
},
|
15
|
+
"devDependencies": {
|
16
|
+
"cross-env": "^7.0.3",
|
17
|
+
"jest": "^28.1.3",
|
18
|
+
"prettier": "^2.7.1"
|
19
|
+
},
|
20
|
+
"directories": {
|
21
|
+
"lib": "lib"
|
22
|
+
},
|
23
|
+
"files": [
|
24
|
+
"lib"
|
25
|
+
],
|
26
|
+
"keywords": [
|
27
|
+
"motoko",
|
28
|
+
"language",
|
29
|
+
"programming-language",
|
30
|
+
"dfinity",
|
31
|
+
"smart-contract",
|
32
|
+
"canister",
|
33
|
+
"browser",
|
34
|
+
"ic",
|
35
|
+
"icp",
|
36
|
+
"internet-computer",
|
37
|
+
"blockchain",
|
38
|
+
"cryptocurrency",
|
39
|
+
"nft",
|
40
|
+
"token"
|
41
|
+
]
|
42
|
+
}
|