motoko 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|