motoko 2.0.5 → 2.0.8

Sign up to get free protection for your applications and to get access to all the features.
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
+ // },
@@ -0,0 +1,4 @@
1
+ import getMotoko from '..';
2
+ const { Motoko } = require('../../versions/latest/moc_interpreter.min');
3
+
4
+ export default getMotoko(Motoko, 'latest/interpreter');
@@ -0,0 +1,4 @@
1
+ import getMotoko from '..';
2
+ const { Motoko } = require('../../versions/latest/moc.min');
3
+
4
+ export default getMotoko(Motoko, 'latest');