motoko 3.0.0-beta1 → 3.0.0-beta2

Sign up to get free protection for your applications and to get access to all the features.
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,8 +60,8 @@ export const file = (mo: Motoko, path: string) => {
60
60
  parseMotoko() {
61
61
  return mo.parseMotoko(result.read());
62
62
  },
63
- parseMotokoTypes() {
64
- return mo.parseMotokoTypes(result.read());
63
+ parseMotokoTyped() {
64
+ return mo.parseMotokoTyped(result.read());
65
65
  },
66
66
  parseCandid() {
67
67
  return mo.parseCandid(result.read());
package/src/index.ts CHANGED
@@ -1,5 +1,12 @@
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';
3
10
  import { resolveMain, resolveLib } from './utils/resolveEntryPoint';
4
11
 
5
12
  export type Motoko = ReturnType<typeof wrapMotoko>;
@@ -22,7 +29,7 @@ export type Diagnostic = {
22
29
  export type WasmMode = 'ic' | 'wasi';
23
30
 
24
31
  export default function wrapMotoko(compiler: Compiler, version: string) {
25
- const debug = require('debug')(version ? `motoko:${version}` : 'motoko');
32
+ const debug = require('debug')(`motoko:${version}`);
26
33
 
27
34
  const invoke = (key: string, unwrap: boolean, args: any[]) => {
28
35
  if (!compiler) {
@@ -87,21 +94,36 @@ export default function wrapMotoko(compiler: Compiler, version: string) {
87
94
  list(directory: string): string[] {
88
95
  return invoke('readDir', false, [directory]);
89
96
  },
90
- async fetchPackage(info: string | PackageInfo) {
91
- return fetchPackage(info);
92
- },
93
- async loadPackages(packages: Record<string, string | PackageInfo>) {
94
- return loadPackages(mo, packages);
95
- },
96
- addPackage(name: string, directory: string) {
97
- 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);
98
117
  invoke('addPackage', false, [name, directory]);
99
118
  },
100
119
  clearPackages() {
101
120
  debug('-packages');
102
121
  invoke('clearPackage', false, []);
103
122
  },
104
- setAliases(aliases: string) {
123
+ validatePackage(pkg: Package) {
124
+ validatePackage(pkg);
125
+ },
126
+ setAliases(aliases: Record<string, string>) {
105
127
  debug('aliases', aliases);
106
128
  invoke('setActorAliases', false, [Object.entries(aliases)]);
107
129
  },
@@ -129,11 +151,16 @@ export default function wrapMotoko(compiler: Compiler, version: string) {
129
151
  }
130
152
  return invoke('compileWasm', true, [mode, path]);
131
153
  },
132
- parseMotoko(content: string): object {
133
- return invoke('parseMotoko', true, [content]);
154
+ parseMotoko(content: string): Node {
155
+ const ast = invoke('parseMotoko', true, [content]);
156
+ return simplifyAST(ast);
134
157
  },
135
- parseMotokoTypes(content: string): { ast: object; outputType: object } {
136
- return invoke('parseMotokoTypes', true, [content]);
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
+ };
137
164
  },
138
165
  parseCandid(content: string): object {
139
166
  return invoke('parseCandid', true, [content]);
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
+ }
@@ -55,10 +55,10 @@ function resolveEntryPoint(
55
55
  // return getOne(parsedFiles.filter());
56
56
  }
57
57
 
58
- export function resolveMain(mo: Motoko, directory: string): string | undefined {
58
+ export function resolveMain(mo: Motoko, directory: string): string {
59
59
  return resolveEntryPoint(mo, directory, 'Main.mo');
60
60
  }
61
61
 
62
- export function resolveLib(mo: Motoko, directory: string): string | undefined {
62
+ export function resolveLib(mo: Motoko, directory: string): string {
63
63
  return resolveEntryPoint(mo, directory, 'Lib.mo');
64
64
  }