functionalscript 0.0.492 → 0.0.494

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/dev/module.mjs CHANGED
@@ -78,9 +78,14 @@ const remove_tail = v => dif => v.slice(0, v.length - dif)
78
78
  /** @type {any} */
79
79
  const self = globalThis
80
80
 
81
+ /** @type {() => Promise<FsPromises>} */
82
+ export const fs = () => import(self.Deno ? 'https://deno.land/std/node/fs/promises.ts' : 'node:fs/promises')
83
+
84
+ /** @type {(code: number) => never} */
85
+ export const exit = self.Deno ? self.Deno.exit : process.exit
86
+
81
87
  export const loadModuleMap = async () => {
82
- /** @type {FsPromises} */
83
- const { readdir, readFile } = await import(self.Deno ? 'https://deno.land/std/node/fs/promises.ts' : 'node:fs/promises')
88
+ const { readdir, readFile } = await fs();
84
89
 
85
90
  /** @type {() => Promise<FunctionMap>} */
86
91
  const load = async () => {
@@ -1,6 +1,7 @@
1
1
  const list = require('../../types/list/module.f.cjs')
2
2
  const { fold } = list
3
- const { reset, fgGreen } = require('../../text/sgr/module.f.cjs')
3
+ const { reset, fgGreen, fgRed, bold } = require('../../text/sgr/module.f.cjs')
4
+ const result = require('../../types/result/module.f.cjs')
4
5
 
5
6
  /**
6
7
  * @typedef {{
@@ -28,7 +29,7 @@ const { reset, fgGreen } = require('../../text/sgr/module.f.cjs')
28
29
 
29
30
  /**
30
31
  * @template T
31
- * @typedef {(state: T) => readonly[number, T]} PerformanceNow
32
+ * @typedef {<R>(f: () => R) => (state: T) => readonly[R, number, T]} Measure
32
33
  */
33
34
 
34
35
  /**
@@ -36,74 +37,92 @@ const { reset, fgGreen } = require('../../text/sgr/module.f.cjs')
36
37
  * @typedef {{
37
38
  * readonly moduleMap: ModuleMap,
38
39
  * readonly log: Log<T>,
39
- * readonly performanceNow: PerformanceNow<T>,
40
+ * readonly measure: Measure<T>,
40
41
  * readonly state: T,
42
+ * readonly tryCatch: <R>(f: () => R) => result.Result<R, unknown>
41
43
  * }} Input
42
44
  */
43
45
 
44
46
  /** @type {(s: string) => boolean} */
45
47
  const isTest = s => s.endsWith('test.f.cjs')
46
48
 
49
+ /**
50
+ * @typedef {{
51
+ * readonly time: number,
52
+ * readonly pass: number,
53
+ * readonly fail: number,
54
+ * }} TestState
55
+ */
56
+
57
+ /** @type {(time: number) => (testState: TestState) => TestState} */
58
+ const addPass = delta => ts => ({ ...ts, time: ts.time + delta, pass: ts.pass + 1 })
59
+
60
+ /** @type {(time: number) => (testState: TestState) => TestState} */
61
+ const addFail = delta => ts => ({ ...ts, time: ts.time + delta, fail: ts.fail + 1 })
62
+
47
63
  /**
48
64
  * @template T
49
- * @typedef {readonly[number, T]} State
65
+ * @typedef {readonly[TestState, T]} FullState
50
66
  */
51
67
 
52
- /** @type {<T>(input: Input<T>) => T} */
68
+ /** @type {<T>(input: Input<T>) => readonly[number, T]} */
53
69
  const main = input => {
54
- let { moduleMap, log, performanceNow, state } = input
70
+ let { moduleMap, log, measure, tryCatch, state } = input
55
71
  /** @typedef {input extends Input<infer T> ? T : never} T */
56
- /** @type {(i: string) => (v: unknown) => (state: State<T>) => State<T>} */
57
- const test = i => v => ([time, state]) => {
72
+ /** @type {(i: string) => (v: unknown) => (fs: FullState<T>) => FullState<T>} */
73
+ const test = i => v => ([ts, state]) => {
58
74
  const next = test(`${i}| `)
59
75
  switch (typeof v) {
60
76
  case 'function': {
61
77
  if (v.length === 0) {
62
- let b = 0;
63
- [b, state] = performanceNow(state)
64
- const r = v()
65
- let e = 0;
66
- [e, state] = performanceNow(state)
67
- const delta = e - b
68
- time += delta
69
- state = log(`${i}() ${fgGreen}ok${reset}, ${delta} ms`)(state);
70
- [time, state] = next(r)([time, state])
78
+ const [[s, r], delta, state0] = measure(() => tryCatch(/** @type {() => unknown} */(v)))(state)
79
+ state = state0
80
+ if (s === 'error') {
81
+ ts = addFail(delta)(ts)
82
+ state = log(`${i}() ${fgRed}error${reset}, ${delta} ms`)(state)
83
+ state = log(`${fgRed}${r}${reset}`)(state)
84
+ } else {
85
+ ts = addPass(delta)(ts)
86
+ state = log(`${i}() ${fgGreen}ok${reset}, ${delta} ms`)(state)
87
+ }
88
+ [ts, state] = next(r)([ts, state])
71
89
  }
72
90
  break
73
91
  }
74
92
  case 'object': {
75
93
  if (v !== null) {
76
- /** @type {(k: readonly[string|number, unknown]) => (state: State<T>) => State<T>} */
94
+ /** @type {(k: readonly[string|number, unknown]) => (fs: FullState<T>) => FullState<T>} */
77
95
  const f = ([k, v]) => ([time, state]) => {
78
96
  state = log(`${i}${k}:`)(state);
79
97
  [time, state] = next(v)([time, state])
80
98
  return [time, state]
81
99
  }
82
- [time, state] = fold
100
+ [ts, state] = fold
83
101
  (f)
84
- ([time, state])
102
+ ([ts, state])
85
103
  (v instanceof Array ? list.entries(v) : Object.entries(v))
86
104
  }
87
105
  break
88
106
  }
89
107
  }
90
- return [time, state]
108
+ return [ts, state]
91
109
  }
92
110
  const next = test('| ')
93
- /** @type {(k: readonly[string, Module]) => (fs: State<T>) => State<T>} */
94
- const f = ([k, v]) => ([time, state]) => {
111
+ /** @type {(k: readonly[string, Module]) => (fs: FullState<T>) => FullState<T>} */
112
+ const f = ([k, v]) => ([ts, state]) => {
95
113
  if (isTest(k)) {
96
114
  state = log(`testing ${k}`)(state);
97
- [time, state] = next(v.exports)([time, state])
115
+ [ts, state] = next(v.exports)([ts, state])
98
116
  }
99
- return [time, state]
117
+ return [ts, state]
100
118
  }
101
- /** @type {State<T>} */
102
- const init = [0, state]
103
- let time = 0;
104
- [time, state] = fold(f)(init)(Object.entries(moduleMap))
105
- state = log(`total ${time} ms`)(state);
106
- return state
119
+ /** @type {TestState} */
120
+ let ts = { time: 0, pass: 0, fail: 0 };
121
+ [ts, state] = fold(f)([ts, state])(Object.entries(moduleMap))
122
+ const fgFail = ts.fail === 0 ? fgGreen : fgRed
123
+ state = log(`${bold}Number of tests: pass: ${fgGreen}${ts.pass}${reset}${bold}, fail: ${fgFail}${ts.fail}${reset}${bold}, total: ${ts.pass + ts.fail}${reset}`)(state)
124
+ state = log(`${bold}Time: ${ts.time} ms${reset}`)(state);
125
+ return [ts.fail !== 0 ? 1 : 0, state]
107
126
  }
108
127
 
109
- module.exports = main
128
+ module.exports = main
package/dev/test.mjs CHANGED
@@ -1,13 +1,46 @@
1
- import { loadModuleMap } from './module.mjs'
1
+ import { loadModuleMap, exit } from './module.mjs'
2
+
3
+ const consoleLog = console.log
2
4
 
3
5
  /** @type {(s: string) => <T>(_: T) => T} */
4
6
  const log = s => state => {
5
- console.log(s)
7
+ consoleLog(s)
6
8
  return state
7
9
  }
8
10
 
9
- /** @type {<T>(_: T) => readonly[number, T]} */
10
- const performanceNow = state => [performance.now(), state]
11
+ /**
12
+ * @template T
13
+ * @typedef {readonly['ok', T]} Ok
14
+ */
15
+
16
+ /**
17
+ * @template E
18
+ * @typedef {readonly['error', E]} Error
19
+ */
20
+
21
+ /**
22
+ * @template T
23
+ * @template E
24
+ * @typedef {Ok<T>|Error<E>} Result
25
+ */
26
+
27
+ /** @type {<T>(f: () => T) => Result<T, unknown>} */
28
+ const tryCatch = f => {
29
+ // Side effect: `try catch` is not allowed in FunctionalScript.
30
+ try {
31
+ return ['ok', f()]
32
+ } catch (e) {
33
+ return ['error', e]
34
+ }
35
+ }
36
+
37
+ /** @type {<R>(f: () => R) => <T>(state: T) => readonly[R, number, T]} Measure} */
38
+ const measure = f => state => {
39
+ const b = performance.now()
40
+ const r = f()
41
+ const e = performance.now()
42
+ return [r, e - b, state]
43
+ }
11
44
 
12
45
  // test runner.
13
46
  const main = async() => {
@@ -15,11 +48,13 @@ const main = async() => {
15
48
 
16
49
  /** @type {any} */
17
50
  const f = moduleMap['./dev/test/module.f.cjs'].exports
18
- f({
51
+ const r = f({
19
52
  moduleMap,
20
53
  log,
21
- performanceNow,
54
+ measure,
55
+ tryCatch,
22
56
  })
57
+ exit(r[0])
23
58
  }
24
59
 
25
60
  main()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.0.492",
3
+ "version": "0.0.494",
4
4
  "description": "FunctionalScript is a functional subset of JavaScript",
5
5
  "main": "module.f.cjs",
6
6
  "scripts": {
@@ -13,5 +13,7 @@ module.exports = {
13
13
  /** @readonly */
14
14
  bold: sgr(1),
15
15
  /** @readonly */
16
+ fgRed: sgr(31),
17
+ /** @readonly */
16
18
  fgGreen: sgr(32),
17
19
  }