motoko 3.0.0-beta0 → 3.0.0-beta2

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,24 +17,25 @@ declare const _default: {
17
17
  };
18
18
  candid(): string;
19
19
  wasm(mode: import("..").WasmMode): any;
20
- parseMotoko(): {
21
- ast: object;
22
- exportType: object;
23
- };
24
- parseCandid(): {
25
- ast: object;
20
+ parseMotoko(): import("../ast").Node;
21
+ parseMotokoTyped(): {
22
+ ast: import("../ast").Node;
23
+ type: import("../ast").Node;
26
24
  };
25
+ parseCandid(): object;
27
26
  };
28
27
  read(path: string): string;
29
28
  write(path: string, content?: string): void;
30
29
  rename(path: string, newPath: string): void;
31
30
  delete(path: string): void;
32
31
  list(directory: string): string[];
33
- fetchPackage(info: string | import("../package").PackageInfo): Promise<import("../package").Package>;
34
- loadPackages(packages: Record<string, string | import("../package").PackageInfo>): Promise<void>;
35
- addPackage(name: string, directory: string): void;
32
+ fetchPackage(name: string, info: string | import("../package").PackageInfo): Promise<import("../package").Package>;
33
+ installPackages(packages: Record<string, string | import("../package").PackageInfo>): Promise<void>;
34
+ loadPackage(pkg: import("../package").Package): void;
35
+ usePackage(name: string, directory: string): void;
36
36
  clearPackages(): void;
37
- setAliases(aliases: string): void;
37
+ validatePackage(pkg: import("../package").Package): void;
38
+ setAliases(aliases: Record<string, string>): void;
38
39
  setMetadata(values: string): void;
39
40
  check(path: string): import("..").Diagnostic[];
40
41
  run(path: string, libPaths?: string[]): {
@@ -44,13 +45,14 @@ declare const _default: {
44
45
  };
45
46
  candid(path: string): string;
46
47
  wasm(path: string, mode: import("..").WasmMode): any;
47
- parseMotoko(content: string): {
48
- ast: object;
49
- exportType: object;
50
- };
51
- parseCandid(content: string): {
52
- ast: object;
48
+ parseMotoko(content: string): import("../ast").Node;
49
+ parseMotokoTyped(content: string): {
50
+ ast: import("../ast").Node;
51
+ type: import("../ast").Node;
53
52
  };
53
+ parseCandid(content: string): object;
54
+ resolveMain(directory?: string): string;
55
+ resolveLib(directory?: string): string;
54
56
  };
55
57
  export default _default;
56
58
  //# sourceMappingURL=interpreter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interpreter.d.ts","sourceRoot":"","sources":["../../src/versions/interpreter.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,wBAAwD"}
1
+ {"version":3,"file":"interpreter.d.ts","sourceRoot":"","sources":["../../src/versions/interpreter.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,wBAAwD"}
@@ -17,24 +17,25 @@ declare const _default: {
17
17
  };
18
18
  candid(): string;
19
19
  wasm(mode: import("..").WasmMode): any;
20
- parseMotoko(): {
21
- ast: object;
22
- exportType: object;
23
- };
24
- parseCandid(): {
25
- ast: object;
20
+ parseMotoko(): import("../ast").Node;
21
+ parseMotokoTyped(): {
22
+ ast: import("../ast").Node;
23
+ type: import("../ast").Node;
26
24
  };
25
+ parseCandid(): object;
27
26
  };
28
27
  read(path: string): string;
29
28
  write(path: string, content?: string): void;
30
29
  rename(path: string, newPath: string): void;
31
30
  delete(path: string): void;
32
31
  list(directory: string): string[];
33
- fetchPackage(info: string | import("../package").PackageInfo): Promise<import("../package").Package>;
34
- loadPackages(packages: Record<string, string | import("../package").PackageInfo>): Promise<void>;
35
- addPackage(name: string, directory: string): void;
32
+ fetchPackage(name: string, info: string | import("../package").PackageInfo): Promise<import("../package").Package>;
33
+ installPackages(packages: Record<string, string | import("../package").PackageInfo>): Promise<void>;
34
+ loadPackage(pkg: import("../package").Package): void;
35
+ usePackage(name: string, directory: string): void;
36
36
  clearPackages(): void;
37
- setAliases(aliases: string): void;
37
+ validatePackage(pkg: import("../package").Package): void;
38
+ setAliases(aliases: Record<string, string>): void;
38
39
  setMetadata(values: string): void;
39
40
  check(path: string): import("..").Diagnostic[];
40
41
  run(path: string, libPaths?: string[]): {
@@ -44,13 +45,14 @@ declare const _default: {
44
45
  };
45
46
  candid(path: string): string;
46
47
  wasm(path: string, mode: import("..").WasmMode): any;
47
- parseMotoko(content: string): {
48
- ast: object;
49
- exportType: object;
50
- };
51
- parseCandid(content: string): {
52
- ast: object;
48
+ parseMotoko(content: string): import("../ast").Node;
49
+ parseMotokoTyped(content: string): {
50
+ ast: import("../ast").Node;
51
+ type: import("../ast").Node;
53
52
  };
53
+ parseCandid(content: string): object;
54
+ resolveMain(directory?: string): string;
55
+ resolveLib(directory?: string): string;
54
56
  };
55
57
  export default _default;
56
58
  //# sourceMappingURL=moc.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"moc.d.ts","sourceRoot":"","sources":["../../src/versions/moc.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,wBAA4C"}
1
+ {"version":3,"file":"moc.d.ts","sourceRoot":"","sources":["../../src/versions/moc.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,wBAA4C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "motoko",
3
- "version": "3.0.0-beta0",
3
+ "version": "3.0.0-beta2",
4
4
  "description": "Compile and run Motoko smart contracts in Node.js or the browser.",
5
5
  "author": "Ryan Vandersmith (https://github.com/rvanasa)",
6
6
  "license": "Apache-2.0",
@@ -21,7 +21,8 @@
21
21
  "dependencies": {
22
22
  "cross-fetch": "3.1.5",
23
23
  "debug": "4.3.4",
24
- "isomorphic-parse-github-url": "1.0.2"
24
+ "isomorphic-parse-github-url": "1.0.2",
25
+ "sanitize-filename": "^1.6.3"
25
26
  },
26
27
  "devDependencies": {
27
28
  "@types/jest": "^28.1.3",
package/src/ast.ts ADDED
@@ -0,0 +1,69 @@
1
+ export type CompilerAST = CompilerAST[] | CompilerNode | string | null;
2
+ export type CompilerSpan = { name: 'Pos'; args: [string, string, string] };
3
+
4
+ export interface CompilerNode {
5
+ name: string;
6
+ args: CompilerAST[];
7
+ }
8
+
9
+ export type Span = [number, number];
10
+ export type AST = AST[] | Node | string | null;
11
+
12
+ export interface Node {
13
+ name: string;
14
+ file?: string;
15
+ start?: Span;
16
+ end?: Span;
17
+ type?: Node;
18
+ args?: AST[];
19
+ }
20
+
21
+ // export type TypeAST = AST[] | Node | string | number | null;
22
+ // export type TypeNode = {
23
+ // name: string;
24
+ // args: TypeAST[];
25
+ // };
26
+
27
+ export function simplifyAST(ast: CompilerNode): Node;
28
+ export function simplifyAST(ast: CompilerAST[]): AST[];
29
+ export function simplifyAST<T extends CompilerAST>(ast: T): T;
30
+
31
+ export function simplifyAST(ast: CompilerAST): AST {
32
+ if (Array.isArray(ast)) {
33
+ return ast.map((a) => simplifyAST(a));
34
+ }
35
+ if (typeof ast !== 'object') {
36
+ return ast;
37
+ }
38
+ if (ast.name === '@') {
39
+ const [start, end, subAst] = ast.args as [
40
+ CompilerSpan,
41
+ CompilerSpan,
42
+ CompilerAST,
43
+ ];
44
+ return {
45
+ ...(typeof subAst === 'string'
46
+ ? { name: subAst }
47
+ : simplifyAST(subAst)),
48
+ file: start.args[0],
49
+ start: [+start.args[1], +start.args[2]],
50
+ end: [+end.args[1], +end.args[2]],
51
+ };
52
+ }
53
+ if (ast.name === ':') {
54
+ const [type, subAst] = ast.args as [CompilerNode, CompilerAST];
55
+ // console.log(subAst); ////
56
+ return {
57
+ ...(typeof subAst === 'string'
58
+ ? { name: subAst }
59
+ : simplifyAST(subAst)),
60
+ type: simplifyAST(type),
61
+ };
62
+ }
63
+ return {
64
+ name: ast.name,
65
+ args: simplifyAST(ast.args),
66
+ };
67
+ }
68
+
69
+ // export function getTypeString(type: Type) {}
package/src/file.ts CHANGED
@@ -60,6 +60,9 @@ export const file = (mo: Motoko, path: string) => {
60
60
  parseMotoko() {
61
61
  return mo.parseMotoko(result.read());
62
62
  },
63
+ parseMotokoTyped() {
64
+ return mo.parseMotokoTyped(result.read());
65
+ },
63
66
  parseCandid() {
64
67
  return mo.parseCandid(result.read());
65
68
  },
package/src/index.ts CHANGED
@@ -1,5 +1,13 @@
1
+ import { Node, simplifyAST } from './ast';
1
2
  import { file } from './file';
2
- import { fetchPackage, loadPackages, PackageInfo } from './package';
3
+ import {
4
+ fetchPackage,
5
+ installPackages,
6
+ Package,
7
+ PackageInfo,
8
+ validatePackage,
9
+ } from './package';
10
+ import { resolveMain, resolveLib } from './utils/resolveEntryPoint';
3
11
 
4
12
  export type Motoko = ReturnType<typeof wrapMotoko>;
5
13
 
@@ -21,7 +29,7 @@ export type Diagnostic = {
21
29
  export type WasmMode = 'ic' | 'wasi';
22
30
 
23
31
  export default function wrapMotoko(compiler: Compiler, version: string) {
24
- const debug = require('debug')(version ? `motoko:${version}` : 'motoko');
32
+ const debug = require('debug')(`motoko:${version}`);
25
33
 
26
34
  const invoke = (key: string, unwrap: boolean, args: any[]) => {
27
35
  if (!compiler) {
@@ -86,21 +94,36 @@ export default function wrapMotoko(compiler: Compiler, version: string) {
86
94
  list(directory: string): string[] {
87
95
  return invoke('readDir', false, [directory]);
88
96
  },
89
- async fetchPackage(info: string | PackageInfo) {
90
- return fetchPackage(info);
91
- },
92
- async loadPackages(packages: Record<string, string | PackageInfo>) {
93
- return loadPackages(mo, packages);
94
- },
95
- addPackage(name: string, directory: string) {
96
- debug('+package', name, directory);
97
+ async fetchPackage(name:string, info: string | PackageInfo) {
98
+ if(!info){
99
+ throw new Error('Please specify both a name and source');
100
+ }
101
+ return fetchPackage(name,info);
102
+ },
103
+ async installPackages(packages: Record<string, string | PackageInfo>) {
104
+ return installPackages(mo, packages);
105
+ },
106
+ loadPackage(pkg: Package) {
107
+ debug('+package', pkg.name);
108
+ mo.validatePackage(pkg);
109
+ const directory = `.node-motoko/${pkg.name}/${pkg.version}`;
110
+ Object.entries(pkg.files).forEach(([path, file]) => {
111
+ mo.write(`${directory}/${path}`, file.content);
112
+ });
113
+ mo.usePackage(pkg.name, directory);
114
+ },
115
+ usePackage(name: string, directory: string) {
116
+ debug('@package', name, directory);
97
117
  invoke('addPackage', false, [name, directory]);
98
118
  },
99
119
  clearPackages() {
100
120
  debug('-packages');
101
121
  invoke('clearPackage', false, []);
102
122
  },
103
- setAliases(aliases: string) {
123
+ validatePackage(pkg: Package) {
124
+ validatePackage(pkg);
125
+ },
126
+ setAliases(aliases: Record<string, string>) {
104
127
  debug('aliases', aliases);
105
128
  invoke('setActorAliases', false, [Object.entries(aliases)]);
106
129
  },
@@ -128,12 +151,26 @@ export default function wrapMotoko(compiler: Compiler, version: string) {
128
151
  }
129
152
  return invoke('compileWasm', true, [mode, path]);
130
153
  },
131
- parseMotoko(content: string): { ast: object; exportType: object } {
132
- return invoke('parseMotoko', true, [content]);
154
+ parseMotoko(content: string): Node {
155
+ const ast = invoke('parseMotoko', true, [content]);
156
+ return simplifyAST(ast);
133
157
  },
134
- parseCandid(content: string): { ast: object } {
158
+ parseMotokoTyped(content: string): { ast: Node; type: Node } {
159
+ const { ast, typ } = invoke('parseMotokoTyped', true, [content]);
160
+ return {
161
+ ast: simplifyAST(ast),
162
+ type: simplifyAST(typ),
163
+ };
164
+ },
165
+ parseCandid(content: string): object {
135
166
  return invoke('parseCandid', true, [content]);
136
167
  },
168
+ resolveMain(directory: string = ''): string | undefined {
169
+ return resolveMain(mo, directory);
170
+ },
171
+ resolveLib(directory: string = ''): string | undefined {
172
+ return resolveLib(mo, directory);
173
+ },
137
174
  };
138
175
  // @ts-ignore
139
176
  mo.default = mo;
package/src/package.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  import { default as parse } from 'isomorphic-parse-github-url';
5
5
  import fetch from 'cross-fetch';
6
6
  import { Motoko } from '.';
7
+ import sanitize from 'sanitize-filename';
7
8
 
8
9
  export interface PackageInfo {
9
10
  name: string;
@@ -42,7 +43,7 @@ async function loadPackage(mo: Motoko, info: PackageInfo) {
42
43
  };
43
44
  const result = await fetchGithub_(mo, repo, info.name);
44
45
  if (result) {
45
- mo.addPackage(info.name, info.name + '/');
46
+ mo.usePackage(info.name, info.name + '/');
46
47
  }
47
48
  return result ? true : false;
48
49
  }
@@ -279,6 +280,7 @@ async function fetchFromService(
279
280
  }
280
281
 
281
282
  export async function fetchPackage(
283
+ name: string,
282
284
  info: string | PackageInfo,
283
285
  ): Promise<Package | undefined> {
284
286
  if (typeof info === 'string') {
@@ -289,13 +291,13 @@ export async function fetchPackage(
289
291
  return;
290
292
  }
291
293
  return {
292
- name: info.name,
294
+ name,
293
295
  version: info.version,
294
296
  files,
295
297
  };
296
298
  }
297
299
 
298
- export async function loadPackages(
300
+ export async function installPackages(
299
301
  mo: Motoko,
300
302
  packages: Record<string, string | PackageInfo>,
301
303
  ) {
@@ -309,3 +311,54 @@ export async function loadPackages(
309
311
  }),
310
312
  );
311
313
  }
314
+
315
+ export function validatePackage(pkg: Package) {
316
+ function showValue(value: any) {
317
+ const string = JSON.stringify(value);
318
+ return string.length > 50 ? string.substring(0, 50) + '...' : string;
319
+ }
320
+ function getPackageDisplayName() {
321
+ return `(${pkg.name} / ${pkg.version})`;
322
+ }
323
+
324
+ if (typeof pkg !== 'object' || Array.isArray(pkg)) {
325
+ throw new Error(`Unexpected package: ${showValue(pkg)}`);
326
+ }
327
+ if (typeof pkg.name !== 'string' || sanitize(pkg.name) !== pkg.name) {
328
+ throw new Error(`Invalid package name ${getPackageDisplayName()}`);
329
+ }
330
+ if (
331
+ typeof pkg.version !== 'string' ||
332
+ sanitize(pkg.version) !== pkg.version
333
+ ) {
334
+ throw new Error(`Invalid package version ${getPackageDisplayName()}`);
335
+ }
336
+ if (typeof pkg.files !== 'object' || Array.isArray(pkg.files)) {
337
+ throw new Error(`Invalid package files: ${showValue(pkg.files)}`);
338
+ }
339
+
340
+ Object.entries(pkg.files).forEach(([path, file]) => {
341
+ if (
342
+ typeof path !== 'string' ||
343
+ path.split('/').some((p) => sanitize(p) !== p)
344
+ ) {
345
+ throw new Error(
346
+ `Invalid file path ${getPackageDisplayName()} [${path}]`,
347
+ );
348
+ }
349
+ if (typeof file !== 'object' || Array.isArray(file)) {
350
+ throw new Error(
351
+ `Invalid file ${getPackageDisplayName()} [${path}]: ${showValue(
352
+ file,
353
+ )}`,
354
+ );
355
+ }
356
+ if (typeof file.content !== 'string') {
357
+ throw new Error(
358
+ `Invalid file content ${getPackageDisplayName()} [${path}]: ${showValue(
359
+ file.content,
360
+ )}`,
361
+ );
362
+ }
363
+ });
364
+ }
@@ -0,0 +1,64 @@
1
+ import { Motoko } from '..';
2
+
3
+ // function getOne<T>(values: T[]): T | undefined {
4
+ // if (values.length) {
5
+ // return values[0];
6
+ // }
7
+ // }
8
+
9
+ function resolveEntryPoint(
10
+ mo: Motoko,
11
+ directory: string,
12
+ expected: string,
13
+ ): string {
14
+ directory = directory || '';
15
+ if (directory && !directory.endsWith('/')) {
16
+ directory += '/';
17
+ }
18
+
19
+ const moFiles = mo.list(directory).filter((f) => /\.mo$/i.test(f));
20
+ if (moFiles.length === 1) {
21
+ return moFiles[0];
22
+ } else if (moFiles.length === 0) {
23
+ throw new Error(
24
+ 'Could not find any Motoko files in the top-level directory',
25
+ );
26
+ }
27
+
28
+ const expectedFiles = moFiles.filter(
29
+ (f) => f.toLowerCase() === expected.toLowerCase(),
30
+ );
31
+ if (expectedFiles.length === 1) {
32
+ return expectedFiles[0];
33
+ } else if (expectedFiles.length > 1) {
34
+ throw new Error(
35
+ `Found ${expectedFiles.length} entry point files with different capitalization`,
36
+ );
37
+ }
38
+
39
+ throw new Error(
40
+ `Found ${moFiles.length} possible entry points. Please rename one of these files to '${expected}'`,
41
+ );
42
+
43
+ // TODO: evaluate whether we want to choose an entry point by parsing files
44
+
45
+ // const parsedFiles = moFiles.map((f) => {
46
+ // try {
47
+ // return mo.parseMotoko(mo.read(directory + f));
48
+ // } catch (err) {
49
+ // throw new Error(`Parse error in ${f}`);
50
+ // }
51
+ // });
52
+
53
+ // console.log(parsedFiles);
54
+
55
+ // return getOne(parsedFiles.filter());
56
+ }
57
+
58
+ export function resolveMain(mo: Motoko, directory: string): string {
59
+ return resolveEntryPoint(mo, directory, 'Main.mo');
60
+ }
61
+
62
+ export function resolveLib(mo: Motoko, directory: string): string {
63
+ return resolveEntryPoint(mo, directory, 'Lib.mo');
64
+ }