motoko 2.0.6 → 2.0.9
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 +2 -2
- package/contrib/monaco.js +65 -52
- package/index.js +1 -4
- package/interpreter.js +1 -4
- package/lib/file.d.ts +22 -0
- package/lib/file.d.ts.map +1 -0
- package/lib/file.js +7 -5
- package/lib/file.js.map +1 -0
- package/lib/index.d.ts +69 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +39 -34
- package/lib/index.js.map +1 -0
- package/lib/package.d.ts +10 -0
- package/lib/package.d.ts.map +1 -0
- package/lib/package.js +125 -120
- package/lib/package.js.map +1 -0
- package/lib/versions/interpreter.d.ts +45 -0
- package/lib/versions/interpreter.d.ts.map +1 -0
- package/lib/versions/interpreter.js +9 -0
- package/lib/versions/interpreter.js.map +1 -0
- package/lib/versions/moc.d.ts +45 -0
- package/lib/versions/moc.d.ts.map +1 -0
- package/lib/versions/moc.js +9 -0
- package/lib/versions/moc.js.map +1 -0
- package/package.json +16 -7
- package/src/file.ts +68 -0
- package/src/index.ts +139 -0
- package/src/package.ts +185 -0
- package/src/versions/interpreter.ts +4 -0
- package/src/versions/moc.ts +4 -0
- package/lib/__tests__/index.test.js +0 -40
- package/lib/__tests__/interpreter.test.js +0 -15
package/src/index.ts
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
import { file } from './file';
|
2
|
+
import { loadPackages, PackageInfo } from './package';
|
3
|
+
|
4
|
+
export type Motoko = ReturnType<typeof getMotoko>;
|
5
|
+
|
6
|
+
type Compiler = any; // TODO
|
7
|
+
|
8
|
+
// TODO
|
9
|
+
export type Diagnostic = {
|
10
|
+
code?: string | number | { target: any; value: string | number };
|
11
|
+
message: string;
|
12
|
+
range: {
|
13
|
+
start: { line: number; character: number };
|
14
|
+
end: { line: number; character: number };
|
15
|
+
};
|
16
|
+
severity: string;
|
17
|
+
source?: string;
|
18
|
+
tags?: string[];
|
19
|
+
};
|
20
|
+
|
21
|
+
export type WasmMode = 'ic' | 'wasi';
|
22
|
+
|
23
|
+
export default function getMotoko(compiler: Compiler, version: string) {
|
24
|
+
const debug = require('debug')(version ? `motoko:${version}` : 'motoko');
|
25
|
+
|
26
|
+
const invoke = (key: string, unwrap: boolean, args: any[]) => {
|
27
|
+
if (!compiler) {
|
28
|
+
throw new Error(
|
29
|
+
'Please load a Motoko compiler before running this function',
|
30
|
+
);
|
31
|
+
}
|
32
|
+
if (typeof compiler[key] !== 'function') {
|
33
|
+
throw new Error(`Unknown compiler function: '${key}'`);
|
34
|
+
}
|
35
|
+
let result;
|
36
|
+
try {
|
37
|
+
result = compiler[key](...args);
|
38
|
+
} catch (err) {
|
39
|
+
if (err instanceof Error) {
|
40
|
+
throw err;
|
41
|
+
}
|
42
|
+
throw new Error(
|
43
|
+
`Unable to execute ${key}(${[...args]
|
44
|
+
.map((x) => typeof x)
|
45
|
+
.join(', ')}):\n${JSON.stringify(err)}`,
|
46
|
+
);
|
47
|
+
}
|
48
|
+
if (!unwrap) {
|
49
|
+
return result;
|
50
|
+
}
|
51
|
+
if (!result.code) {
|
52
|
+
throw new Error(
|
53
|
+
result.diagnostics
|
54
|
+
? result.diagnostics
|
55
|
+
.map(({ message }: Diagnostic) => message)
|
56
|
+
.join('; ')
|
57
|
+
: '(no diagnostics)',
|
58
|
+
);
|
59
|
+
}
|
60
|
+
return result.code;
|
61
|
+
};
|
62
|
+
|
63
|
+
const mo = {
|
64
|
+
version,
|
65
|
+
compiler,
|
66
|
+
file(path: string) {
|
67
|
+
return file(mo, path);
|
68
|
+
},
|
69
|
+
// findPackage,
|
70
|
+
async loadPackages(packages: Record<string, string | PackageInfo>) {
|
71
|
+
return loadPackages(mo, packages);
|
72
|
+
},
|
73
|
+
read(path: string): string {
|
74
|
+
return invoke('readFile', false, [path]);
|
75
|
+
},
|
76
|
+
write(path: string, content: string = '') {
|
77
|
+
if (typeof content !== 'string') {
|
78
|
+
throw new Error('Non-string file content');
|
79
|
+
}
|
80
|
+
debug('+file', path);
|
81
|
+
invoke('saveFile', false, [path, content]);
|
82
|
+
},
|
83
|
+
rename(path: string, newPath: string) {
|
84
|
+
invoke('renameFile', false, [path, newPath]);
|
85
|
+
},
|
86
|
+
delete(path: string) {
|
87
|
+
debug('-file', path);
|
88
|
+
invoke('removeFile', false, [path]);
|
89
|
+
},
|
90
|
+
list(directory: string): string[] {
|
91
|
+
return invoke('readDir', false, [directory]);
|
92
|
+
},
|
93
|
+
addPackage(name: string, directory: string) {
|
94
|
+
debug('+package', name, directory);
|
95
|
+
invoke('addPackage', false, [name, directory]);
|
96
|
+
},
|
97
|
+
clearPackages() {
|
98
|
+
debug('-packages');
|
99
|
+
invoke('clearPackage', false, []);
|
100
|
+
},
|
101
|
+
setAliases(aliases: string) {
|
102
|
+
debug('aliases', aliases);
|
103
|
+
invoke('setActorAliases', false, [Object.entries(aliases)]);
|
104
|
+
},
|
105
|
+
setMetadata(values: string) {
|
106
|
+
invoke('setPublicMetadata', false, [values]);
|
107
|
+
},
|
108
|
+
check(path: string): Diagnostic[] {
|
109
|
+
const result = invoke('check', false, [path]);
|
110
|
+
return result.diagnostics;
|
111
|
+
},
|
112
|
+
run(
|
113
|
+
path: string,
|
114
|
+
libPaths?: string[] | undefined,
|
115
|
+
): { stdout: string; stderr: string; result: number | string } {
|
116
|
+
return invoke('run', false, [libPaths || [], path]);
|
117
|
+
},
|
118
|
+
candid(path: string): string {
|
119
|
+
return invoke('candid', true, [path]);
|
120
|
+
},
|
121
|
+
wasm(path: string, mode: WasmMode) {
|
122
|
+
if (!mode) {
|
123
|
+
mode = 'ic';
|
124
|
+
} else if (mode !== 'ic' && mode !== 'wasi') {
|
125
|
+
throw new Error(`Invalid WASM format: ${mode}`);
|
126
|
+
}
|
127
|
+
return invoke('compileWasm', true, [mode, path]);
|
128
|
+
},
|
129
|
+
parseMotoko(content: string): object {
|
130
|
+
return invoke('parseMotoko', true, [content]);
|
131
|
+
},
|
132
|
+
parseCandid(content: string): object {
|
133
|
+
return invoke('parseCandid', true, [content]);
|
134
|
+
},
|
135
|
+
};
|
136
|
+
// @ts-ignore
|
137
|
+
mo.default = mo;
|
138
|
+
return mo;
|
139
|
+
}
|
package/src/package.ts
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
// Derived from: https://github.com/dfinity/motoko-playground/blob/main/src/workers/file.ts
|
2
|
+
|
3
|
+
// @ts-ignore
|
4
|
+
import { default as parse } from 'isomorphic-parse-github-url';
|
5
|
+
import fetch from 'cross-fetch';
|
6
|
+
import { Motoko } from '.';
|
7
|
+
|
8
|
+
export interface PackageInfo {
|
9
|
+
name: string;
|
10
|
+
repo: string;
|
11
|
+
version: string;
|
12
|
+
dir: string;
|
13
|
+
branch?: string | undefined;
|
14
|
+
}
|
15
|
+
|
16
|
+
async function fetchPackage(mo: Motoko, info: PackageInfo) {
|
17
|
+
if (
|
18
|
+
!info.repo.startsWith('https://github.com/') ||
|
19
|
+
!info.repo.endsWith('.git')
|
20
|
+
) {
|
21
|
+
return false;
|
22
|
+
}
|
23
|
+
const repo = {
|
24
|
+
name: info.name,
|
25
|
+
version: info.version,
|
26
|
+
repo: info.repo.slice(0, -4).replace(/^(https:\/\/github.com\/)/, ''),
|
27
|
+
branch: info.version,
|
28
|
+
dir: info.dir || 'src',
|
29
|
+
};
|
30
|
+
const result = await fetchGithub(mo, repo, info.name);
|
31
|
+
if (result) {
|
32
|
+
mo.addPackage(info.name, info.name + '/');
|
33
|
+
}
|
34
|
+
return result ? true : false;
|
35
|
+
}
|
36
|
+
|
37
|
+
async function fetchGithub(mo: Motoko, info: PackageInfo, directory = '') {
|
38
|
+
const possiblyCDN = !(
|
39
|
+
(info.branch.length % 2 === 0 && /^[A-F0-9]+$/i.test(info.branch)) ||
|
40
|
+
info.branch === 'master' ||
|
41
|
+
info.branch === 'main'
|
42
|
+
);
|
43
|
+
if (possiblyCDN) {
|
44
|
+
const result = await fetchFromCDN(mo, info, directory);
|
45
|
+
if (result) {
|
46
|
+
return result;
|
47
|
+
}
|
48
|
+
}
|
49
|
+
return await fetchFromGithub(mo, info, directory);
|
50
|
+
}
|
51
|
+
|
52
|
+
// function saveWorkplaceToMotoko(mo, files) {
|
53
|
+
// for (const [name, code] of Object.entries(files)) {
|
54
|
+
// if (!name.endsWith('mo')) continue;
|
55
|
+
// mo.addFile(name, code);
|
56
|
+
// }
|
57
|
+
// }
|
58
|
+
|
59
|
+
async function fetchFromCDN(mo: Motoko, info: PackageInfo, directory = '') {
|
60
|
+
const meta_url = `https://data.jsdelivr.com/v1/package/gh/${info.repo}@${info.branch}/flat`;
|
61
|
+
const base_url = `https://cdn.jsdelivr.net/gh/${info.repo}@${info.branch}`;
|
62
|
+
const response = await fetch(meta_url);
|
63
|
+
const json = await response.json();
|
64
|
+
if (!json.hasOwnProperty('files')) {
|
65
|
+
throw new Error(json.message || `Could not fetch from CDN: ${info}`);
|
66
|
+
}
|
67
|
+
const promises: Promise<void>[] = [];
|
68
|
+
const files: Record<string, string> = {};
|
69
|
+
for (const f of json.files) {
|
70
|
+
if (f.name.startsWith(`/${info.dir}/`) && /\.mo$/.test(f.name)) {
|
71
|
+
const promise = (async () => {
|
72
|
+
const content = await (await fetch(base_url + f.name)).text();
|
73
|
+
const stripped =
|
74
|
+
directory +
|
75
|
+
f.name.slice(info.dir ? info.dir.length + 1 : 0);
|
76
|
+
mo.write(stripped, content);
|
77
|
+
files[stripped] = content;
|
78
|
+
})();
|
79
|
+
promises.push(promise);
|
80
|
+
}
|
81
|
+
}
|
82
|
+
if (!promises.length) {
|
83
|
+
return;
|
84
|
+
}
|
85
|
+
return Promise.all(promises).then(() => {
|
86
|
+
return files;
|
87
|
+
});
|
88
|
+
}
|
89
|
+
|
90
|
+
async function fetchFromGithub(
|
91
|
+
mo: Motoko,
|
92
|
+
info: PackageInfo,
|
93
|
+
directory: string = '',
|
94
|
+
) {
|
95
|
+
const meta_url = `https://api.github.com/repos/${info.repo}/git/trees/${info.branch}?recursive=1`;
|
96
|
+
const base_url = `https://raw.githubusercontent.com/${info.repo}/${info.branch}/`;
|
97
|
+
const response = await fetch(meta_url);
|
98
|
+
const json = await response.json();
|
99
|
+
if (!json.hasOwnProperty('tree')) {
|
100
|
+
throw new Error(
|
101
|
+
json.message || `Could not fetch from GitHub repository: ${info}`,
|
102
|
+
);
|
103
|
+
}
|
104
|
+
const promises: Promise<void>[] = [];
|
105
|
+
const files: Record<string, string> = {};
|
106
|
+
for (const f of json.tree) {
|
107
|
+
if (
|
108
|
+
f.path.startsWith(info.dir ? `${info.dir}/` : '') &&
|
109
|
+
f.type === 'blob' &&
|
110
|
+
/\.mo$/.test(f.path)
|
111
|
+
) {
|
112
|
+
const promise = (async () => {
|
113
|
+
const content = await (await fetch(base_url + f.path)).text();
|
114
|
+
const stripped =
|
115
|
+
directory +
|
116
|
+
(directory ? '/' : '') +
|
117
|
+
f.path.slice(info.dir ? info.dir.length + 1 : 0);
|
118
|
+
mo.write(stripped, content);
|
119
|
+
files[stripped] = content;
|
120
|
+
})();
|
121
|
+
promises.push(promise);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
if (!promises.length) {
|
125
|
+
return;
|
126
|
+
}
|
127
|
+
return Promise.all(promises).then(() => {
|
128
|
+
return files;
|
129
|
+
});
|
130
|
+
}
|
131
|
+
|
132
|
+
// async function resolve(path) {
|
133
|
+
|
134
|
+
// }
|
135
|
+
|
136
|
+
function parseGithubPackage(
|
137
|
+
path: string | PackageInfo,
|
138
|
+
name: string,
|
139
|
+
): PackageInfo {
|
140
|
+
if (!path) {
|
141
|
+
return;
|
142
|
+
}
|
143
|
+
if (typeof path === 'object') {
|
144
|
+
return path;
|
145
|
+
}
|
146
|
+
|
147
|
+
let result;
|
148
|
+
try {
|
149
|
+
result = parse(path);
|
150
|
+
if (!result) {
|
151
|
+
return;
|
152
|
+
}
|
153
|
+
} catch (err) {
|
154
|
+
console.warn(err);
|
155
|
+
}
|
156
|
+
|
157
|
+
const { name: repoName, filepath, branch, owner } = result;
|
158
|
+
|
159
|
+
return {
|
160
|
+
name: name || repoName,
|
161
|
+
repo: `https://github.com/${owner}/${repoName}.git`,
|
162
|
+
version: branch,
|
163
|
+
dir: filepath,
|
164
|
+
// homepage: ,
|
165
|
+
};
|
166
|
+
}
|
167
|
+
|
168
|
+
export async function loadPackages(
|
169
|
+
mo: Motoko,
|
170
|
+
packages: Record<string, string | PackageInfo>,
|
171
|
+
) {
|
172
|
+
await Promise.all(
|
173
|
+
Object.entries(packages).map(([name, path]) => {
|
174
|
+
const info = parseGithubPackage(path, name);
|
175
|
+
return fetchPackage(mo, info);
|
176
|
+
}),
|
177
|
+
);
|
178
|
+
}
|
179
|
+
|
180
|
+
// export async function findPackage(package) {
|
181
|
+
// if (typeof package === 'string') {
|
182
|
+
// return resolve(package);
|
183
|
+
// }
|
184
|
+
// return package;
|
185
|
+
// },
|
@@ -1,40 +0,0 @@
|
|
1
|
-
'use strict';
|
2
|
-
|
3
|
-
const mo = require('../..');
|
4
|
-
|
5
|
-
const actor = `
|
6
|
-
actor Main {
|
7
|
-
public func test() : async Nat {
|
8
|
-
123
|
9
|
-
}
|
10
|
-
}
|
11
|
-
`;
|
12
|
-
|
13
|
-
describe('virtual file system I/O', () => {
|
14
|
-
test('write -> read', () => {
|
15
|
-
const path = 'test__write_read__.txt';
|
16
|
-
const text = 'A\nB';
|
17
|
-
mo.write(path, text);
|
18
|
-
expect(mo.read(path)).toStrictEqual(text);
|
19
|
-
});
|
20
|
-
});
|
21
|
-
|
22
|
-
describe('check', () => {
|
23
|
-
test('works for a basic example', () => {
|
24
|
-
const path = 'test__check__.mo';
|
25
|
-
mo.write(path, actor);
|
26
|
-
expect(mo.check(path)).toStrictEqual([]);
|
27
|
-
});
|
28
|
-
});
|
29
|
-
|
30
|
-
describe('run', () => {
|
31
|
-
test('works for a basic example', () => {
|
32
|
-
const path = 'test__run__.mo';
|
33
|
-
mo.write(path, 'let x = 1 + 1; x');
|
34
|
-
expect(mo.run(path)).toStrictEqual({
|
35
|
-
result: 0,
|
36
|
-
stdout: '2 : Nat\n',
|
37
|
-
stderr: '',
|
38
|
-
});
|
39
|
-
});
|
40
|
-
});
|
@@ -1,15 +0,0 @@
|
|
1
|
-
'use strict';
|
2
|
-
|
3
|
-
const mo = require('../../interpreter');
|
4
|
-
|
5
|
-
describe('run', () => {
|
6
|
-
test('works for a basic example', () => {
|
7
|
-
const path = 'test__run__.mo';
|
8
|
-
mo.write(path, 'let x = 1 + 1; x');
|
9
|
-
expect(mo.run(path)).toStrictEqual({
|
10
|
-
result: 0,
|
11
|
-
stdout: '2 : Nat\n',
|
12
|
-
stderr: '',
|
13
|
-
});
|
14
|
-
});
|
15
|
-
});
|