motoko 0.1.0

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