functionalscript 0.5.0 → 0.6.0

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.
Files changed (50) hide show
  1. package/README.md +1 -1
  2. package/dev/index.d.ts +1 -0
  3. package/dev/index.js +3 -0
  4. package/dev/module.f.d.ts +11 -0
  5. package/dev/module.f.js +55 -0
  6. package/dev/test/module.d.ts +1 -0
  7. package/dev/test/module.f.d.ts +7 -8
  8. package/dev/test/module.f.js +23 -3
  9. package/dev/test/module.js +3 -0
  10. package/dev/test.f.d.ts +1 -0
  11. package/dev/test.f.js +4 -0
  12. package/{nodejs → dev}/version/module.f.d.ts +1 -1
  13. package/{nodejs → dev}/version/module.f.js +1 -1
  14. package/{nodejs → dev}/version/test.f.js +1 -4
  15. package/djs/module.f.d.ts +1 -1
  16. package/djs/module.f.js +3 -2
  17. package/djs/parser/module.f.d.ts +2 -2
  18. package/djs/parser/module.f.js +1 -1
  19. package/djs/transpiler/module.f.d.ts +2 -2
  20. package/djs/transpiler/module.f.js +1 -1
  21. package/djs/transpiler/test.f.js +2 -2
  22. package/fsc/module.d.ts +2 -0
  23. package/fsc/module.js +4 -0
  24. package/io/module.d.ts +4 -0
  25. package/io/module.f.d.ts +68 -0
  26. package/io/module.f.js +16 -1
  27. package/io/module.js +36 -0
  28. package/io/virtual.f.d.ts +3 -0
  29. package/io/virtual.f.js +28 -0
  30. package/js/tokenizer/module.f.js +1 -1
  31. package/json/parser/module.f.d.ts +2 -2
  32. package/json/parser/module.f.js +4 -7
  33. package/package.json +15 -15
  34. package/types/map/module.f.d.ts +2 -12
  35. package/types/map/module.f.js +16 -21
  36. package/types/map/test.f.d.ts +2 -2
  37. package/types/map/test.f.js +17 -109
  38. package/types/object/module.f.d.ts +2 -2
  39. package/types/object/module.f.js +1 -1
  40. package/types/ordered_map/module.f.d.ts +12 -0
  41. package/types/ordered_map/module.f.js +22 -0
  42. package/types/ordered_map/test.f.d.ts +5 -0
  43. package/types/ordered_map/test.f.js +113 -0
  44. package/types/result/module.d.ts +5 -0
  45. package/types/result/module.js +13 -0
  46. package/fsc.js +0 -4
  47. package/io/node-io.js +0 -7
  48. package/io/virtual-io.f.d.ts +0 -3
  49. package/io/virtual-io.f.js +0 -14
  50. /package/{nodejs → dev}/version/test.f.d.ts +0 -0
package/README.md CHANGED
@@ -31,7 +31,7 @@ FunctionalScript code can be used:
31
31
 
32
32
  - safely in any JavaScript/TypeScript application or library;
33
33
  - as a JSON with expressions, see [DJS](https://medium.com/@sasha.gil/bridging-the-gap-from-json-to-javascript-without-dsls-fee273573f1b);
34
- - as a query language,
34
+ - as a query language;
35
35
  - as a smart contract programming language in DeFi.
36
36
 
37
37
  ## Design Principles
package/dev/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dev/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { index } from "./module.f.js";
2
+ import node from "../io/module.js";
3
+ await node(index);
package/dev/module.f.d.ts CHANGED
@@ -1 +1,12 @@
1
+ import type { Io } from '../io/module.f.ts';
1
2
  export declare const todo: () => never;
3
+ export type Module = {
4
+ readonly default?: unknown;
5
+ };
6
+ export type ModuleMap = {
7
+ readonly [k in string]: Module;
8
+ };
9
+ export declare const env: (io: Io) => (v: string) => string | undefined;
10
+ export declare const allFiles: ({ fs: { promises: { readdir } } }: Io) => Promise<readonly string[]>;
11
+ export declare const loadModuleMap: (io: Io) => Promise<ModuleMap>;
12
+ export declare const index: (io: Io) => Promise<number>;
package/dev/module.f.js CHANGED
@@ -1 +1,56 @@
1
+ import { updateVersion } from "./version/module.f.js";
1
2
  export const todo = () => { throw 'not implemented'; };
3
+ const cmp = ([a], [b]) => a < b ? -1 : a > b ? 1 : 0;
4
+ export const env = ({ process: { env } }) => a => {
5
+ const r = Object.getOwnPropertyDescriptor(env, a);
6
+ return r === undefined ? undefined :
7
+ typeof r.get === 'function' ? r.get() :
8
+ r.value;
9
+ };
10
+ export const allFiles = ({ fs: { promises: { readdir } } }) => {
11
+ const load = async (p) => {
12
+ let result = [];
13
+ for (const i of await readdir(p, { withFileTypes: true })) {
14
+ const { name } = i;
15
+ if (!name.startsWith('.')) {
16
+ const file = `${p}/${name}`;
17
+ if (i.isDirectory()) {
18
+ result = [...result, ...await load(file)];
19
+ continue;
20
+ }
21
+ if (name.endsWith('.js') || name.endsWith('.ts')) {
22
+ result = [...result, file];
23
+ }
24
+ }
25
+ }
26
+ return result;
27
+ };
28
+ return load('.');
29
+ };
30
+ export const loadModuleMap = async (io) => {
31
+ const { fs: { existsSync }, asyncImport } = io;
32
+ let map = [];
33
+ for (const f of await allFiles(io)) {
34
+ if (f.endsWith('.f.js') ||
35
+ (f.endsWith('.f.ts') && !existsSync(f.substring(0, f.length - 3) + '.js'))) {
36
+ const source = await asyncImport(`../${f}`);
37
+ map = [...map, [f, source]];
38
+ }
39
+ }
40
+ return Object.fromEntries(map.toSorted(cmp));
41
+ };
42
+ export const index = async (io) => {
43
+ updateVersion(io);
44
+ const jj = './deno.json';
45
+ const jsr_json = JSON.parse(await io.fs.promises.readFile(jj, 'utf8'));
46
+ const list = (await allFiles(io)).filter(v => v.endsWith('/module.f.ts') || v.endsWith('/module.ts'));
47
+ //console.log(list)
48
+ const exportsA = list.map(v => [v, `./${v.substring(2)}`]);
49
+ // console.log(exportsA)
50
+ const exports = Object.fromEntries(exportsA);
51
+ // console.log(exports)
52
+ const json = JSON.stringify({ ...jsr_json, exports }, null, 2);
53
+ // console.log(json)
54
+ await io.fs.promises.writeFile(jj, json, 'utf8');
55
+ return 0;
56
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,10 +1,6 @@
1
1
  import type * as Result from '../../types/result/module.f.ts';
2
- type Module = {
3
- readonly default?: unknown;
4
- };
5
- type ModuleMap = {
6
- readonly [k in string]: Module;
7
- };
2
+ import type { Io, Performance } from '../../io/module.f.ts';
3
+ import { type ModuleMap } from '../module.f.ts';
8
4
  type Log<T> = (v: string) => (state: T) => T;
9
5
  type Measure<T> = <R>(f: () => R) => (state: T) => readonly [R, number, T];
10
6
  type Input<T> = {
@@ -16,5 +12,8 @@ type Input<T> = {
16
12
  readonly tryCatch: <R>(f: () => R) => Result.Result<R, unknown>;
17
13
  readonly env: (n: string) => string | undefined;
18
14
  };
19
- declare const _default: <T>(input: Input<T>) => readonly [number, T];
20
- export default _default;
15
+ export declare const test: <T>(input: Input<T>) => readonly [number, T];
16
+ export declare const anyLog: (f: (s: string) => void) => (s: string) => <T>(state: T) => T;
17
+ export declare const measure: (p: Performance) => <R>(f: () => R) => <T>(state: T) => readonly [R, number, T];
18
+ export declare const main: (io: Io) => Promise<number>;
19
+ export {};
@@ -1,6 +1,7 @@
1
1
  import { entries, fold } from "../../types/list/module.f.js";
2
2
  import { reset, fgGreen, fgRed, bold } from "../../text/sgr/module.f.js";
3
- const isTest = (s) => s.endsWith('test.f.mjs') || s.endsWith('test.f.js') || s.endsWith('test.f.ts');
3
+ import { env, loadModuleMap } from "../module.f.js";
4
+ const isTest = (s) => s.endsWith('test.f.js') || s.endsWith('test.f.ts');
4
5
  const addPass = (delta) => (ts) => ({ ...ts, time: ts.time + delta, pass: ts.pass + 1 });
5
6
  const addFail = (delta) => (ts) => ({ ...ts, time: ts.time + delta, fail: ts.fail + 1 });
6
7
  const timeFormat = (a) => {
@@ -12,9 +13,9 @@ const timeFormat = (a) => {
12
13
  const e = x.substring(s);
13
14
  return `${b}.${e} ms`;
14
15
  };
15
- export default (input) => {
16
+ export const test = (input) => {
16
17
  let { moduleMap, log, error, measure, tryCatch, env, state } = input;
17
- const isGitHub = env('GITHUB_ACTION') !== void 0;
18
+ const isGitHub = env('GITHUB_ACTION') !== undefined;
18
19
  const f = ([k, v]) => {
19
20
  const test = i => v => ([ts, state]) => {
20
21
  const next = test(`${i}| `);
@@ -73,3 +74,22 @@ export default (input) => {
73
74
  state = log(`${bold}Time: ${timeFormat(ts.time)}${reset}`)(state);
74
75
  return [ts.fail !== 0 ? 1 : 0, state];
75
76
  };
77
+ export const anyLog = (f) => (s) => (state) => {
78
+ f(s);
79
+ return state;
80
+ };
81
+ export const measure = (p) => (f) => (state) => {
82
+ const b = p.now();
83
+ const r = f();
84
+ const e = p.now();
85
+ return [r, e - b, state];
86
+ };
87
+ export const main = async (io) => test({
88
+ moduleMap: await loadModuleMap(io),
89
+ log: anyLog(io.console.log),
90
+ error: anyLog(io.console.error),
91
+ measure: measure(io.performance),
92
+ tryCatch: io.tryCatch,
93
+ env: env(io),
94
+ state: undefined,
95
+ })[0];
@@ -0,0 +1,3 @@
1
+ import { main } from "./module.f.js";
2
+ import node from "../../io/module.js";
3
+ await node(main);
package/dev/test.f.d.ts CHANGED
@@ -5,5 +5,6 @@ declare const _default: {
5
5
  number: () => void;
6
6
  properties: () => void;
7
7
  getOwnPropertyDescriptor: () => void;
8
+ throw: () => void;
8
9
  };
9
10
  export default _default;
package/dev/test.f.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { todo } from "./module.f.js";
1
2
  export default {
2
3
  ctor: () => {
3
4
  const c = (() => { })['constructor'];
@@ -48,5 +49,8 @@ export default {
48
49
  const x = { 'a': 12 };
49
50
  const c = Object.getOwnPropertyDescriptor(x, 'constructor');
50
51
  const a = Object.getOwnPropertyDescriptor(x, 'a');
52
+ },
53
+ throw: () => {
54
+ todo();
51
55
  }
52
56
  };
@@ -1,6 +1,6 @@
1
1
  export type Buffer = object;
2
2
  type Fs<T> = {
3
- readonly readFileSync: (name: string) => Buffer;
3
+ readonly readFileSync: (name: string, encoding: 'utf8') => string;
4
4
  readonly writeFileSync: (name: string, content: string) => T;
5
5
  };
6
6
  export type Node<T> = {
@@ -1,7 +1,7 @@
1
1
  const { stringify, parse } = JSON;
2
2
  export const getVersion = fs => readJson(fs)('package').version;
3
3
  const jsonFile = (jsonFile) => `${jsonFile}.json`;
4
- const readJson = fs => name => parse(fs.readFileSync(jsonFile(name)).toString());
4
+ const readJson = fs => name => parse(fs.readFileSync(jsonFile(name), 'utf8'));
5
5
  export const updateVersion = ({ fs }) => {
6
6
  const f = (name) => {
7
7
  return fs.writeFileSync(jsonFile(name), stringify({
@@ -73,13 +73,10 @@ const e = '{\n' +
73
73
  ' "typescript": "^4.7.4"\n' +
74
74
  ' }\n' +
75
75
  '}';
76
- const buffer = s => ({
77
- toString: () => s
78
- });
79
76
  export default () => {
80
77
  const node = {
81
78
  fs: {
82
- readFileSync: n => buffer(JSON.stringify(x[n])),
79
+ readFileSync: n => JSON.stringify(x[n]),
83
80
  writeFileSync: (_, content) => content
84
81
  }
85
82
  };
package/djs/module.f.d.ts CHANGED
@@ -6,4 +6,4 @@ export type Object = {
6
6
  export type Array = readonly Unknown[];
7
7
  export type Primitive = JsonPrimitive | bigint | undefined;
8
8
  export type Unknown = Primitive | Object | Array;
9
- export declare const run: ({ console: { error }, fs, process: { argv } }: Io) => void;
9
+ export declare const compile: ({ console: { error }, fs, process: { argv } }: Io) => Promise<number>;
package/djs/module.f.js CHANGED
@@ -2,11 +2,11 @@ import { transpile } from "./transpiler/module.f.js";
2
2
  import { stringify } from "./serializer/module.f.js";
3
3
  import { sort } from "../types/object/module.f.js";
4
4
  const stringifyUnknown = stringify(sort);
5
- export const run = ({ console: { error }, fs, process: { argv } }) => {
5
+ export const compile = ({ console: { error }, fs, process: { argv } }) => {
6
6
  const args = argv.slice(2);
7
7
  if (args.length < 2) {
8
8
  error('Error: Requires 2 or more arguments');
9
- return;
9
+ return Promise.resolve(1);
10
10
  }
11
11
  const inputFileName = args[0];
12
12
  const outputFileName = args[1];
@@ -22,4 +22,5 @@ export const run = ({ console: { error }, fs, process: { argv } }) => {
22
22
  break;
23
23
  }
24
24
  }
25
+ return Promise.resolve(0);
25
26
  };
@@ -1,12 +1,12 @@
1
1
  import * as result from '../../types/result/module.f.ts';
2
2
  import { type List } from '../../types/list/module.f.ts';
3
3
  import type { DjsToken } from '../tokenizer/module.f.ts';
4
- import { type Map } from '../../types/map/module.f.ts';
4
+ import { type OrderedMap } from '../../types/ordered_map/module.f.ts';
5
5
  import type { Fs } from '../../io/module.f.ts';
6
6
  import type { AstModule } from '../ast/module.f.ts';
7
7
  export type ParseContext = {
8
8
  readonly fs: Fs;
9
- readonly complete: Map<result.Result<AstModule, string>>;
9
+ readonly complete: OrderedMap<result.Result<AstModule, string>>;
10
10
  readonly stack: List<string>;
11
11
  };
12
12
  export declare const parseFromTokens: (tokenList: List<DjsToken>) => result.Result<AstModule, string>;
@@ -1,6 +1,6 @@
1
1
  import * as result from "../../types/result/module.f.js";
2
2
  import { fold, first, drop, toArray, length, concat } from "../../types/list/module.f.js";
3
- import { setReplace, at } from "../../types/map/module.f.js";
3
+ import { setReplace, at } from "../../types/ordered_map/module.f.js";
4
4
  import { fromMap } from "../../types/object/module.f.js";
5
5
  const parseInitialOp = token => state => {
6
6
  switch (token.kind) {
@@ -1,11 +1,11 @@
1
1
  import type * as djs from '../module.f.ts';
2
2
  import { type Result } from '../../types/result/module.f.ts';
3
3
  import { type List } from '../../types/list/module.f.ts';
4
- import { type Map } from '../../types/map/module.f.ts';
4
+ import { type OrderedMap } from '../../types/ordered_map/module.f.ts';
5
5
  import type { Fs } from '../../io/module.f.ts';
6
6
  export type ParseContext = {
7
7
  readonly fs: Fs;
8
- readonly complete: Map<djsResult>;
8
+ readonly complete: OrderedMap<djsResult>;
9
9
  readonly stack: List<string>;
10
10
  readonly error: string | null;
11
11
  };
@@ -1,7 +1,7 @@
1
1
  import { error, ok } from "../../types/result/module.f.js";
2
2
  import { fold, drop, map as listMap, toArray, includes } from "../../types/list/module.f.js";
3
3
  import { tokenize } from "../tokenizer/module.f.js";
4
- import { setReplace, at } from "../../types/map/module.f.js";
4
+ import { setReplace, at } from "../../types/ordered_map/module.f.js";
5
5
  import { stringToList } from "../../text/utf16/module.f.js";
6
6
  import { concat as pathConcat } from "../../path/module.f.js";
7
7
  import { parseFromTokens } from "../parser/module.f.js";
@@ -1,8 +1,8 @@
1
1
  import { sort } from "../../types/object/module.f.js";
2
- import { setReplace } from "../../types/map/module.f.js";
2
+ import { setReplace } from "../../types/ordered_map/module.f.js";
3
3
  import { transpile } from "./module.f.js";
4
4
  import { stringify } from "../serializer/module.f.js";
5
- import { createVirtualIo } from "../../io/virtual-io.f.js";
5
+ import { createVirtualIo } from "../../io/virtual.f.js";
6
6
  const virtualFs = map => {
7
7
  return createVirtualIo(map).fs;
8
8
  };
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/fsc/module.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import node from "../io/module.js";
3
+ import { compile } from "../djs/module.f.js";
4
+ await node(compile);
package/io/module.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { type Io, type Run } from './module.f.ts';
2
+ export declare const io: Io;
3
+ declare const runDefault: Run;
4
+ export default runDefault;
package/io/module.f.d.ts CHANGED
@@ -1,17 +1,85 @@
1
+ import type { Result } from '../types/result/module.f.ts';
2
+ /**
3
+ * Standard Node.js buffer encoding type
4
+ * @see https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings
5
+ */
1
6
  export type BufferEncoding = 'utf8';
7
+ /**
8
+ * Represents a directory entry (file or directory) in the filesystem
9
+ * @see https://nodejs.org/api/fs.html#class-fsdirent
10
+ */
11
+ export type Dirent = {
12
+ readonly name: string;
13
+ readonly isDirectory: () => boolean;
14
+ readonly isFile: () => boolean;
15
+ };
16
+ /**
17
+ * File system operations interface
18
+ * @see https://nodejs.org/api/fs.html
19
+ */
2
20
  export type Fs = {
3
21
  readonly writeFileSync: (file: string, data: string) => void;
4
22
  readonly readFileSync: (path: string, options: BufferEncoding) => string | null;
23
+ readonly existsSync: (path: string) => boolean;
24
+ readonly promises: {
25
+ readonly readFile: (path: string, options: BufferEncoding) => Promise<string>;
26
+ readonly writeFile: (path: string, data: string, options: BufferEncoding) => Promise<void>;
27
+ readonly readdir: (path: string, options: {
28
+ withFileTypes: true;
29
+ }) => Promise<Dirent[]>;
30
+ };
5
31
  };
32
+ /**
33
+ * Console operations interface
34
+ * @see https://nodejs.org/api/console.html
35
+ */
6
36
  export type Console = {
7
37
  readonly log: (...d: unknown[]) => void;
8
38
  readonly error: (...d: unknown[]) => void;
9
39
  };
40
+ /**
41
+ * Represents an ES module with a default export
42
+ */
43
+ export type Module = {
44
+ readonly default: unknown;
45
+ };
46
+ /**
47
+ * High-resolution time measurement interface
48
+ * @see https://nodejs.org/api/perf_hooks.html#performance-now
49
+ */
50
+ export type Performance = {
51
+ readonly now: () => number;
52
+ };
53
+ /**
54
+ * Core IO operations interface providing access to system resources
55
+ */
10
56
  export type Io = {
11
57
  readonly console: Console;
12
58
  readonly fs: Fs;
13
59
  readonly process: Process;
60
+ readonly asyncImport: (s: string) => Promise<Module>;
61
+ readonly performance: Performance;
62
+ readonly tryCatch: <T>(f: () => T) => Result<T, unknown>;
63
+ readonly asyncTryCatch: <T>(f: () => Promise<T>) => Promise<Result<T, unknown>>;
14
64
  };
65
+ /**
66
+ * Node.js Process interface
67
+ * @see https://nodejs.org/api/process.html
68
+ */
15
69
  export type Process = {
16
70
  readonly argv: string[];
71
+ readonly env: Env;
72
+ readonly exit: (code: number) => never;
73
+ };
74
+ /**
75
+ * The environment variables.
76
+ */
77
+ export type Env = {
78
+ readonly [k: string]: string | undefined;
17
79
  };
80
+ export type Run = (f: (io: Io) => Promise<number>) => Promise<never>;
81
+ /**
82
+ * Runs a function and exits the process with the returned code
83
+ * Handles errors by exiting with code 1
84
+ */
85
+ export declare const run: (io: Io) => Run;
package/io/module.f.js CHANGED
@@ -1 +1,16 @@
1
- export {};
1
+ /**
2
+ * Runs a function and exits the process with the returned code
3
+ * Handles errors by exiting with code 1
4
+ */
5
+ export const run = (io) => {
6
+ const code = ([x, b]) => {
7
+ if (x === 'error') {
8
+ io.console.error(x[1]);
9
+ return 1;
10
+ }
11
+ else {
12
+ return b;
13
+ }
14
+ };
15
+ return async (f) => io.process.exit(code(await io.asyncTryCatch(() => f(io))));
16
+ };
package/io/module.js ADDED
@@ -0,0 +1,36 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { run } from "./module.f.js";
10
+ import fs from 'node:fs';
11
+ import process from "node:process";
12
+ export const io = {
13
+ console,
14
+ fs,
15
+ process,
16
+ asyncImport: (v) => import(__rewriteRelativeImportExtension(v)),
17
+ performance,
18
+ tryCatch: f => {
19
+ try {
20
+ return ['ok', f()];
21
+ }
22
+ catch (e) {
23
+ return ['error', e];
24
+ }
25
+ },
26
+ asyncTryCatch: async (f) => {
27
+ try {
28
+ return ['ok', await f()];
29
+ }
30
+ catch (e) {
31
+ return ['error', e];
32
+ }
33
+ },
34
+ };
35
+ const runDefault = run(io);
36
+ export default runDefault;
@@ -0,0 +1,3 @@
1
+ import type { Io } from './module.f.ts';
2
+ import { type OrderedMap } from '../types/ordered_map/module.f.ts';
3
+ export declare const createVirtualIo: (files: OrderedMap<string>) => Io;
@@ -0,0 +1,28 @@
1
+ import { at } from "../types/ordered_map/module.f.js";
2
+ export const createVirtualIo = (files) => ({
3
+ console: {
4
+ log: (..._d) => { },
5
+ error: (..._d) => { }
6
+ },
7
+ fs: {
8
+ writeFileSync: (_file, _data) => { },
9
+ readFileSync: (path, _options) => { return at(path)(files); },
10
+ existsSync: (path) => { return at(path)(files) !== null; },
11
+ promises: {
12
+ readdir: (_path) => Promise.resolve([]),
13
+ readFile: (_path, _options) => Promise.resolve(''),
14
+ writeFile: (_path, _data, _options) => Promise.resolve(),
15
+ }
16
+ },
17
+ process: {
18
+ argv: [],
19
+ env: {},
20
+ exit: n => { throw n; },
21
+ },
22
+ asyncImport: () => Promise.reject(),
23
+ performance: {
24
+ now: () => 0,
25
+ },
26
+ tryCatch: f => ['ok', f()],
27
+ asyncTryCatch: async (f) => ['ok', await f()],
28
+ });
@@ -2,7 +2,7 @@ import * as operator from "../../types/function/operator/module.f.js";
2
2
  import * as range_map from "../../types/range_map/module.f.js";
3
3
  const { merge, fromRange, get } = range_map;
4
4
  import * as list from "../../types/list/module.f.js";
5
- import * as map from "../../types/map/module.f.js";
5
+ import * as map from "../../types/ordered_map/module.f.js";
6
6
  const { at } = map;
7
7
  import * as _range from "../../types/range/module.f.js";
8
8
  const { one } = _range;
@@ -1,5 +1,5 @@
1
1
  import * as result from '../../types/result/module.f.ts';
2
- import * as list from '../../types/list/module.f.ts';
2
+ import { type List } from '../../types/list/module.f.ts';
3
3
  import type * as Tokenizer from '../tokenizer/module.f.ts';
4
4
  import type * as Json from '../module.f.ts';
5
- export declare const parse: (tokenList: list.List<Tokenizer.JsonToken>) => result.Result<Json.Unknown, string>;
5
+ export declare const parse: (tokenList: List<Tokenizer.JsonToken>) => result.Result<Json.Unknown, string>;
@@ -1,13 +1,10 @@
1
1
  import * as result from "../../types/result/module.f.js";
2
- import * as list from "../../types/list/module.f.js";
3
- const { fold, first, drop, toArray } = list;
4
- import * as map from "../../types/map/module.f.js";
5
- const { setReplace } = map;
6
- import * as o from "../../types/object/module.f.js";
7
- const { fromMap } = o;
2
+ import { fold, first, drop, toArray, concat } from "../../types/list/module.f.js";
3
+ import { setReplace } from "../../types/ordered_map/module.f.js";
4
+ import { fromMap } from "../../types/object/module.f.js";
8
5
  const addKeyToObject = obj => key => ({ kind: 'object', values: obj.values, key: key });
9
6
  const addValueToObject = obj => value => ({ kind: 'object', values: setReplace(obj.key)(value)(obj.values), key: '' });
10
- const addToArray = array => value => ({ kind: 'array', values: list.concat(array.values)([value]) });
7
+ const addToArray = array => value => ({ kind: 'array', values: concat(array.values)([value]) });
11
8
  const pushKey = state => value => {
12
9
  if (state.top?.kind === 'object') {
13
10
  return { status: '{k', top: addKeyToObject(state.top)(value), stack: state.stack };
package/package.json CHANGED
@@ -1,29 +1,29 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "files": [
6
- "fsc.js",
7
- "io/node-io.js",
8
- "**/*.f.d.ts",
9
- "**/*.f.js"
6
+ "**/*.js",
7
+ "**/*.d.ts"
10
8
  ],
11
9
  "description": "FunctionalScript is a functional subset of JavaScript",
12
10
  "scripts": {
13
11
  "tsc-emit": "tsc --NoEmit false",
14
- "n": "node --frozen-intrinsics --trace-uncaught",
12
+ "n": "node --trace-uncaught",
15
13
  "prepack": "npm run tsc-emit",
16
14
  "git-clean": "git clean -xf",
17
- "test20": "npm run tsc-emit && npm run n ./dev/test.js",
18
- "test22": "tsc && npm run n -- --experimental-strip-types ./dev/test.ts",
19
- "test": "tsc && npm run n ./dev/test.ts",
15
+ "test20": "npm run tsc-emit && npm run n ./dev/test/module.js",
16
+ "test22": "tsc && npm run n -- --experimental-strip-types ./dev/test/module.ts",
17
+ "test": "tsc && npm run n ./dev/test/module.ts",
20
18
  "index": "npm run n ./dev/index.ts",
21
- "version": "npm run n ./nodejs/version/main.ts",
22
- "fsc": "npm run n ./fsc.ts",
23
- "update": "npm run version && npm run index && npm install"
19
+ "fsc": "npm run n ./fsc/module.ts",
20
+ "update": "npm run index && npm install"
21
+ },
22
+ "engines": {
23
+ "node": ">=16"
24
24
  },
25
25
  "bin": {
26
- "fsc": "fsc.js"
26
+ "fsc": "fsc/module.js"
27
27
  },
28
28
  "repository": {
29
29
  "type": "git",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "homepage": "https://github.com/functionalscript/functionalscript#readme",
47
47
  "devDependencies": {
48
- "@types/node": "^22.13.10",
49
- "typescript": "^5.8.2"
48
+ "@types/node": "^22.14",
49
+ "typescript": "^5.8.3"
50
50
  }
51
51
  }
@@ -1,12 +1,2 @@
1
- import type { Tree } from '../btree/types/module.f.ts';
2
- import { type List } from '../list/module.f.ts';
3
- import type { Reduce } from '../function/operator/module.f.ts';
4
- export type Entry<T> = readonly [string, T];
5
- export type Map<T> = Tree<Entry<T>>;
6
- export declare const at: (name: string) => <T>(map: Map<T>) => T | null;
7
- export declare const setReduce: <T>(reduce: Reduce<T>) => (name: string) => (value: T) => (map: Map<T>) => Map<T>;
8
- export declare const setReplace: (name: string) => <T>(value: T) => (map: Map<T>) => Map<T>;
9
- export declare const entries: <T>(map: Map<T>) => List<Entry<T>>;
10
- export declare const fromEntries: <T>(entries: List<Entry<T>>) => Map<T>;
11
- export declare const remove: (name: string) => <T>(map: Map<T>) => Map<T>;
12
- export declare const empty: null;
1
+ export declare const mapSet: <K, V>(map: ReadonlyMap<K, V>, k: K, v: V) => ReadonlyMap<K, V>;
2
+ export declare const mapDelete: <K, V>(map: ReadonlyMap<K, V>, k: K) => ReadonlyMap<K, V>;
@@ -1,22 +1,17 @@
1
- import { value, find } from "../btree/find/module.f.js";
2
- import { set } from "../btree/set/module.f.js";
3
- import { remove as btreeRemove } from "../btree/remove/module.f.js";
4
- import { values } from "../btree/module.f.js";
5
- import { cmp } from "../string/module.f.js";
6
- import { fold } from "../list/module.f.js";
7
- const keyCmp = a => ([b]) => cmp(a)(b);
8
- export const at = (name) => (map) => {
9
- if (map === null) {
10
- return null;
1
+ const concat = (x, y) => ({
2
+ *[Symbol.iterator]() {
3
+ yield* x;
4
+ yield* y;
11
5
  }
12
- const result = value(find(keyCmp(name))(map).first);
13
- return result === null ? null : result[1];
14
- };
15
- const setReduceEntry = reduce => entry => set(keyCmp(entry[0]))(old => old === null ? entry : [old[0], reduce(old[1])(entry[1])]);
16
- export const setReduce = reduce => name => value => setReduceEntry(reduce)([name, value]);
17
- const replace = () => b => b;
18
- export const setReplace = name => value => setReduceEntry(replace)([name, value]);
19
- export const entries = values;
20
- export const fromEntries = fold(setReduceEntry(replace))(null);
21
- export const remove = name => btreeRemove(keyCmp(name));
22
- export const empty = null;
6
+ });
7
+ const filter = (i, p) => ({
8
+ *[Symbol.iterator]() {
9
+ for (const x of i) {
10
+ if (p(x)) {
11
+ yield x;
12
+ }
13
+ }
14
+ }
15
+ });
16
+ export const mapSet = (map, k, v) => new Map(concat(map, [[k, v]]));
17
+ export const mapDelete = (map, k) => new Map(filter(map, ([xk]) => xk !== k));
@@ -1,5 +1,5 @@
1
1
  declare const _default: {
2
- main: (() => void)[];
3
- stress: () => void;
2
+ set: () => void;
3
+ delete: () => void;
4
4
  };
5
5
  export default _default;
@@ -1,113 +1,21 @@
1
- import { at, setReplace, setReduce, empty, entries, remove } from "./module.f.js";
2
- import { toArray } from "../list/module.f.js";
1
+ import { mapSet, mapDelete } from "./module.f.js";
3
2
  export default {
4
- main: [
5
- () => {
6
- let m = setReplace('a')(1)(null);
7
- if (at('a')(m) !== 1) {
8
- throw 'error';
9
- }
10
- if (at('b')(m) !== null) {
11
- throw 'error';
12
- }
13
- m = setReplace('b')(2)(m);
14
- if (at('a')(m) !== 1) {
15
- throw 'error';
16
- }
17
- if (at('b')(m) !== 2) {
18
- throw 'error';
19
- }
20
- if (at('c')(m) !== null) {
21
- throw 'error';
22
- }
23
- m = setReplace('z')(3)(m);
24
- if (at('a')(m) !== 1) {
25
- throw 'error';
26
- }
27
- if (at('b')(m) !== 2) {
28
- throw 'error';
29
- }
30
- if (at('z')(m) !== 3) {
31
- throw 'error';
32
- }
33
- if (at('')(m) !== null) {
34
- throw 'error';
35
- }
36
- m = setReplace('')(4)(m);
37
- if (at('a')(m) !== 1) {
38
- throw 'error';
39
- }
40
- if (at('b')(m) !== 2) {
41
- throw 'error';
42
- }
43
- if (at('z')(m) !== 3) {
44
- throw 'error';
45
- }
46
- if (at('')(m) !== 4) {
47
- throw 'error';
48
- }
49
- if (at('Hello world!')(m) !== null) {
50
- throw 'error';
51
- }
52
- m = setReplace('Hello world!')(42)(m);
53
- if (at('a')(m) !== 1) {
54
- throw 'error';
55
- }
56
- if (at('b')(m) !== 2) {
57
- throw 'error';
58
- }
59
- if (at('z')(m) !== 3) {
60
- throw 'error';
61
- }
62
- if (at('')(m) !== 4) {
63
- throw 'error';
64
- }
65
- if (at('Hello world!')(m) !== 42) {
66
- throw 'error';
67
- }
68
- if (at('x')(m) !== null) {
69
- throw 'error';
70
- }
71
- // console.log(Array.from(m.entries()))
72
- m = remove('Hello world!')(m);
73
- if (at('Hello world!')(m) !== null) {
74
- throw m;
75
- }
76
- m = setReduce((a) => (b) => a + b)('a')(43)(m);
77
- if (at('a')(m) !== 44) {
78
- throw 'error';
79
- }
80
- },
81
- () => {
82
- let m = setReplace('x')(12)(null);
83
- m = setReplace('y')(44)(m);
84
- if (at('x')(m) !== 12) {
85
- throw 'error';
86
- }
87
- if (at('y')(m) !== 44) {
88
- throw 'error';
89
- }
90
- if (at('a')(m) !== null) {
91
- throw 'error';
92
- }
93
- const e = toArray(entries(m));
94
- if (e.length !== 2) {
95
- throw 'error';
96
- }
97
- },
98
- ],
99
- stress: () => {
100
- let m = empty;
101
- for (let i = 0; i < 100_000; ++i) {
102
- m = setReplace((i * i).toString())(i)(m);
103
- /*
104
- console.log()
105
- console.log(`# ${i}`)
106
- console.log()
107
- for (const e of m.struct()) {
108
- console.log(e)
109
- }
110
- */
3
+ set: () => {
4
+ const map = mapSet(new Map(), 'a', 'b');
5
+ if (map.get('a') !== 'b') {
6
+ throw 'error';
7
+ }
8
+ if (map.size !== 1) {
9
+ throw 'error';
10
+ }
11
+ },
12
+ delete: () => {
13
+ const map = mapDelete(mapSet(new Map(), 'a', 'b'), 'a');
14
+ if (map.get('a') !== undefined) {
15
+ throw 'error';
16
+ }
17
+ if (map.size !== 0) {
18
+ throw 'error';
111
19
  }
112
20
  }
113
21
  };
@@ -1,5 +1,5 @@
1
1
  import { type List } from '../list/module.f.ts';
2
- import { type Map as BtMap } from '../map/module.f.ts';
2
+ import { type OrderedMap } from '../ordered_map/module.f.ts';
3
3
  export type Map<T> = {
4
4
  readonly [k in string]: T;
5
5
  };
@@ -7,7 +7,7 @@ export type Entry<T> = readonly [string, T];
7
7
  export declare const at: (name: string) => <T>(object: Map<T>) => T | null;
8
8
  export declare const sort: <T>(e: List<Entry<T>>) => List<Entry<T>>;
9
9
  export declare const fromEntries: <T>(e: List<Entry<T>>) => Map<T>;
10
- export declare const fromMap: <T>(m: BtMap<T>) => Map<T>;
10
+ export declare const fromMap: <T>(m: OrderedMap<T>) => Map<T>;
11
11
  /**
12
12
  * A set of objects with a single key.
13
13
  *
@@ -1,5 +1,5 @@
1
1
  import { iterable } from "../list/module.f.js";
2
- import { entries as mapEntries, fromEntries as mapFromEntries } from "../map/module.f.js";
2
+ import { entries as mapEntries, fromEntries as mapFromEntries } from "../ordered_map/module.f.js";
3
3
  const { getOwnPropertyDescriptor, fromEntries: objectFromEntries } = Object;
4
4
  export const at = name => object => {
5
5
  const r = getOwnPropertyDescriptor(object, name);
@@ -0,0 +1,12 @@
1
+ import type { Tree } from '../btree/types/module.f.ts';
2
+ import { type List } from '../list/module.f.ts';
3
+ import type { Reduce } from '../function/operator/module.f.ts';
4
+ export type Entry<T> = readonly [string, T];
5
+ export type OrderedMap<T> = Tree<Entry<T>>;
6
+ export declare const at: (name: string) => <T>(map: OrderedMap<T>) => T | null;
7
+ export declare const setReduce: <T>(reduce: Reduce<T>) => (name: string) => (value: T) => (map: OrderedMap<T>) => OrderedMap<T>;
8
+ export declare const setReplace: (name: string) => <T>(value: T) => (map: OrderedMap<T>) => OrderedMap<T>;
9
+ export declare const entries: <T>(map: OrderedMap<T>) => List<Entry<T>>;
10
+ export declare const fromEntries: <T>(entries: List<Entry<T>>) => OrderedMap<T>;
11
+ export declare const remove: (name: string) => <T>(map: OrderedMap<T>) => OrderedMap<T>;
12
+ export declare const empty: null;
@@ -0,0 +1,22 @@
1
+ import { value, find } from "../btree/find/module.f.js";
2
+ import { set } from "../btree/set/module.f.js";
3
+ import { remove as btreeRemove } from "../btree/remove/module.f.js";
4
+ import { values } from "../btree/module.f.js";
5
+ import { cmp } from "../string/module.f.js";
6
+ import { fold } from "../list/module.f.js";
7
+ const keyCmp = a => ([b]) => cmp(a)(b);
8
+ export const at = (name) => (map) => {
9
+ if (map === null) {
10
+ return null;
11
+ }
12
+ const result = value(find(keyCmp(name))(map).first);
13
+ return result === null ? null : result[1];
14
+ };
15
+ const setReduceEntry = reduce => entry => set(keyCmp(entry[0]))(old => old === null ? entry : [old[0], reduce(old[1])(entry[1])]);
16
+ export const setReduce = reduce => name => value => setReduceEntry(reduce)([name, value]);
17
+ const replace = () => b => b;
18
+ export const setReplace = name => value => setReduceEntry(replace)([name, value]);
19
+ export const entries = values;
20
+ export const fromEntries = fold(setReduceEntry(replace))(null);
21
+ export const remove = name => btreeRemove(keyCmp(name));
22
+ export const empty = null;
@@ -0,0 +1,5 @@
1
+ declare const _default: {
2
+ main: (() => void)[];
3
+ stress: () => void;
4
+ };
5
+ export default _default;
@@ -0,0 +1,113 @@
1
+ import { at, setReplace, setReduce, empty, entries, remove } from "./module.f.js";
2
+ import { toArray } from "../list/module.f.js";
3
+ export default {
4
+ main: [
5
+ () => {
6
+ let m = setReplace('a')(1)(null);
7
+ if (at('a')(m) !== 1) {
8
+ throw 'error';
9
+ }
10
+ if (at('b')(m) !== null) {
11
+ throw 'error';
12
+ }
13
+ m = setReplace('b')(2)(m);
14
+ if (at('a')(m) !== 1) {
15
+ throw 'error';
16
+ }
17
+ if (at('b')(m) !== 2) {
18
+ throw 'error';
19
+ }
20
+ if (at('c')(m) !== null) {
21
+ throw 'error';
22
+ }
23
+ m = setReplace('z')(3)(m);
24
+ if (at('a')(m) !== 1) {
25
+ throw 'error';
26
+ }
27
+ if (at('b')(m) !== 2) {
28
+ throw 'error';
29
+ }
30
+ if (at('z')(m) !== 3) {
31
+ throw 'error';
32
+ }
33
+ if (at('')(m) !== null) {
34
+ throw 'error';
35
+ }
36
+ m = setReplace('')(4)(m);
37
+ if (at('a')(m) !== 1) {
38
+ throw 'error';
39
+ }
40
+ if (at('b')(m) !== 2) {
41
+ throw 'error';
42
+ }
43
+ if (at('z')(m) !== 3) {
44
+ throw 'error';
45
+ }
46
+ if (at('')(m) !== 4) {
47
+ throw 'error';
48
+ }
49
+ if (at('Hello world!')(m) !== null) {
50
+ throw 'error';
51
+ }
52
+ m = setReplace('Hello world!')(42)(m);
53
+ if (at('a')(m) !== 1) {
54
+ throw 'error';
55
+ }
56
+ if (at('b')(m) !== 2) {
57
+ throw 'error';
58
+ }
59
+ if (at('z')(m) !== 3) {
60
+ throw 'error';
61
+ }
62
+ if (at('')(m) !== 4) {
63
+ throw 'error';
64
+ }
65
+ if (at('Hello world!')(m) !== 42) {
66
+ throw 'error';
67
+ }
68
+ if (at('x')(m) !== null) {
69
+ throw 'error';
70
+ }
71
+ // console.log(Array.from(m.entries()))
72
+ m = remove('Hello world!')(m);
73
+ if (at('Hello world!')(m) !== null) {
74
+ throw m;
75
+ }
76
+ m = setReduce((a) => (b) => a + b)('a')(43)(m);
77
+ if (at('a')(m) !== 44) {
78
+ throw 'error';
79
+ }
80
+ },
81
+ () => {
82
+ let m = setReplace('x')(12)(null);
83
+ m = setReplace('y')(44)(m);
84
+ if (at('x')(m) !== 12) {
85
+ throw 'error';
86
+ }
87
+ if (at('y')(m) !== 44) {
88
+ throw 'error';
89
+ }
90
+ if (at('a')(m) !== null) {
91
+ throw 'error';
92
+ }
93
+ const e = toArray(entries(m));
94
+ if (e.length !== 2) {
95
+ throw 'error';
96
+ }
97
+ },
98
+ ],
99
+ stress: () => {
100
+ let m = empty;
101
+ for (let i = 0; i < 100_000; ++i) {
102
+ m = setReplace((i * i).toString())(i)(m);
103
+ /*
104
+ console.log()
105
+ console.log(`# ${i}`)
106
+ console.log()
107
+ for (const e of m.struct()) {
108
+ console.log(e)
109
+ }
110
+ */
111
+ }
112
+ }
113
+ };
@@ -0,0 +1,5 @@
1
+ import { type Result } from './module.f.ts';
2
+ declare const _default: {
3
+ readonly tryCatch: <T>(f: () => T) => Result<T, unknown>;
4
+ };
5
+ export default _default;
@@ -0,0 +1,13 @@
1
+ import { ok, error } from "./module.f.js";
2
+ const tryCatch = f => {
3
+ // Side effect: `try catch` is not allowed in FunctionalScript.
4
+ try {
5
+ return ok(f());
6
+ }
7
+ catch (e) {
8
+ return error(e);
9
+ }
10
+ };
11
+ export default {
12
+ tryCatch,
13
+ };
package/fsc.js DELETED
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env node
2
- import io from "./io/node-io.js";
3
- import { run } from "./djs/module.f.js";
4
- run(io);
package/io/node-io.js DELETED
@@ -1,7 +0,0 @@
1
- import fs from 'node:fs';
2
- import process from "node:process";
3
- export default {
4
- console,
5
- fs,
6
- process
7
- };
@@ -1,3 +0,0 @@
1
- import type { Io } from './module.f.ts';
2
- import { type Map } from '../types/map/module.f.ts';
3
- export declare const createVirtualIo: (files: Map<string>) => Io;
@@ -1,14 +0,0 @@
1
- import { at } from "../types/map/module.f.js";
2
- export const createVirtualIo = (files) => ({
3
- console: {
4
- log: (..._d) => { },
5
- error: (..._d) => { }
6
- },
7
- fs: {
8
- writeFileSync: (_file, _data) => { },
9
- readFileSync: (path, _options) => { return at(path)(files); }
10
- },
11
- process: {
12
- argv: []
13
- }
14
- });
File without changes