functionalscript 0.0.268 → 0.0.272
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/README.md +2 -1
- package/commonjs/path/index.js +73 -25
- package/commonjs/path/test.js +92 -3
- package/package.json +1 -1
- package/test.js +4 -3
- package/types/list/index.js +5 -0
- package/types/list/test.js +11 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Try FunctionalScript [here](https://functionalscript.com/).
|
|
|
15
15
|
|
|
16
16
|
In FunctionalScript:
|
|
17
17
|
|
|
18
|
-
- Any module is a valid JavaScript module
|
|
18
|
+
- Any module is a valid JavaScript module. No additional build steps are required.
|
|
19
19
|
- Code should not have [side-effects](https://en.wikipedia.org/wiki/Side_effect_(computer_science)). Any JavaScript statement, expression, or function which has a side effect is not allowed in FunctionalScript. There are no exceptions to this rule, such as `unsafe` code which can be found in Rust, C#, and other languages.
|
|
20
20
|
- A module can't depend on non FunctionalScript module.
|
|
21
21
|
- It also has no standard library, only a safe subset of standard JavaScript API can be used without referencing other modules.
|
|
@@ -172,6 +172,7 @@ The format of an arrow function is `ARGUMENT_NAME => FUNCTION_BODY`. An arrow fu
|
|
|
172
172
|
x => x * 2
|
|
173
173
|
a => a + 4
|
|
174
174
|
s => `template literal ${s}`
|
|
175
|
+
a => b => a + b // an arrow functions that returns another arrow functions.
|
|
175
176
|
() => 'hello' // an arrow function with no arguments
|
|
176
177
|
```
|
|
177
178
|
|
package/commonjs/path/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const
|
|
1
|
+
const list = require("../../types/list")
|
|
2
2
|
const option = require("../../types/option")
|
|
3
3
|
const { compose } = require("../../types/function")
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
4
|
+
const { todo } = require("../../dev")
|
|
5
|
+
const package_ = require("../package")
|
|
6
|
+
const module_ = require("../module")
|
|
7
7
|
|
|
8
8
|
/** @typedef {readonly string[]} Items */
|
|
9
9
|
|
|
@@ -18,32 +18,39 @@ const { at } = require("../../types/object")
|
|
|
18
18
|
/** @type {(path: string) => readonly string[]} */
|
|
19
19
|
const split = path => path.split('/')
|
|
20
20
|
|
|
21
|
-
/** @
|
|
21
|
+
/** @typedef {readonly[list.List<string>] | undefined} OptionList */
|
|
22
|
+
|
|
23
|
+
/** @type {(s: OptionList) => (items: string) => OptionList} */
|
|
22
24
|
const normItemsOp = prior => item => {
|
|
23
25
|
if (prior === undefined) { return undefined }
|
|
26
|
+
const priorList = prior[0]
|
|
24
27
|
switch (item) {
|
|
25
28
|
case '': case '.': { return prior }
|
|
26
29
|
case '..': {
|
|
27
|
-
const result =
|
|
30
|
+
const result = list.next(priorList)
|
|
28
31
|
if (result === undefined) { return undefined }
|
|
29
|
-
return result.tail
|
|
32
|
+
return [result.tail]
|
|
30
33
|
}
|
|
31
34
|
default: {
|
|
32
|
-
return
|
|
35
|
+
return [list.nonEmpty(item)(priorList)]
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
/** @type {(items:
|
|
38
|
-
const normItems =
|
|
40
|
+
/** @type {(items: list.List<string>) => OptionList} */
|
|
41
|
+
const normItems = items => {
|
|
42
|
+
const result = list.reduce(normItemsOp)([undefined])(items)
|
|
43
|
+
if (result === undefined) { return result }
|
|
44
|
+
return [list.reverse(result[0])]
|
|
45
|
+
}
|
|
39
46
|
|
|
40
47
|
/** @type {(local: string) => (path: string) => LocalPath|undefined} */
|
|
41
48
|
const parseLocal = local => {
|
|
42
|
-
/** @type {(path: string) => readonly[boolean,
|
|
49
|
+
/** @type {(path: string) => readonly[boolean, list.List<string>]} */
|
|
43
50
|
const fSeq = path => {
|
|
44
51
|
const pathSeq = split(path)
|
|
45
|
-
switch (
|
|
46
|
-
case '.': case '..': { return [false,
|
|
52
|
+
switch (list.first(undefined)(pathSeq)) {
|
|
53
|
+
case '.': case '..': { return [false, list.flat([split(local), pathSeq])] }
|
|
47
54
|
default: { return [true, pathSeq] }
|
|
48
55
|
}
|
|
49
56
|
}
|
|
@@ -55,18 +62,18 @@ const parseLocal = local => {
|
|
|
55
62
|
return {
|
|
56
63
|
external,
|
|
57
64
|
dir: path[path.length - 1] === '/',
|
|
58
|
-
items:
|
|
65
|
+
items: list.toArray(n[0])
|
|
59
66
|
}
|
|
60
67
|
}
|
|
61
68
|
return f
|
|
62
69
|
}
|
|
63
70
|
|
|
64
|
-
/** @typedef {readonly[string,
|
|
71
|
+
/** @typedef {readonly[string, list.List<string>]} IdPath */
|
|
65
72
|
|
|
66
|
-
/** @type {(prior: readonly[string|undefined,
|
|
73
|
+
/** @type {(prior: readonly[string|undefined, list.List<string>]) => list.Thunk<IdPath>} */
|
|
67
74
|
const variants = prior => () => {
|
|
68
75
|
const [a, b] = prior
|
|
69
|
-
const r =
|
|
76
|
+
const r = list.next(b)
|
|
70
77
|
if (r === undefined) { return undefined }
|
|
71
78
|
const { first, tail } = r
|
|
72
79
|
/** @type {IdPath} */
|
|
@@ -82,35 +89,74 @@ const mapDependency = d => ([external, internal]) => {
|
|
|
82
89
|
|
|
83
90
|
/**
|
|
84
91
|
* @typedef {{
|
|
85
|
-
* readonly
|
|
92
|
+
* readonly packageId: string,
|
|
86
93
|
* readonly items: Items,
|
|
87
94
|
* readonly dir: boolean,
|
|
88
95
|
* }} Path
|
|
89
96
|
*/
|
|
90
97
|
|
|
91
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* @type {(d: (local: string) => string|undefined) =>
|
|
100
|
+
* (dir: boolean) =>
|
|
101
|
+
* (items: list.List<string>) =>
|
|
102
|
+
* Path|undefined}
|
|
103
|
+
*/
|
|
92
104
|
const parseGlobal = d => dir => items => {
|
|
93
105
|
const v = variants([undefined, items])
|
|
94
|
-
const r =
|
|
106
|
+
const r = list.first(undefined)(list.filterMap(mapDependency(d))(v))
|
|
95
107
|
if (r === undefined) { return undefined }
|
|
96
|
-
return {
|
|
108
|
+
return { packageId: r[0], items: list.toArray(r[1]), dir }
|
|
97
109
|
}
|
|
98
110
|
|
|
99
111
|
/**
|
|
100
|
-
* @type {(
|
|
112
|
+
* @type {(packageId: string) =>
|
|
101
113
|
* (dependencies: (local: string) => string|undefined) =>
|
|
102
114
|
* (local: string) =>
|
|
103
115
|
* (path: string) =>
|
|
104
116
|
* Path|undefined }
|
|
105
117
|
*/
|
|
106
|
-
const parse =
|
|
118
|
+
const parse = packageId => dependencies => local => path => {
|
|
107
119
|
const parsed = parseLocal(local)(path)
|
|
108
120
|
if (parsed === undefined) { return undefined }
|
|
109
|
-
const {external, dir, items} = parsed
|
|
110
|
-
if (!external) { return {
|
|
121
|
+
const {external, dir, items } = parsed
|
|
122
|
+
if (!external) { return { packageId, items, dir } }
|
|
111
123
|
return parseGlobal(dependencies)(dir)(items)
|
|
112
124
|
}
|
|
113
125
|
|
|
126
|
+
/**
|
|
127
|
+
* @typedef {{
|
|
128
|
+
* readonly package: string
|
|
129
|
+
* readonly file: string
|
|
130
|
+
* readonly source: string
|
|
131
|
+
* }| undefined} Result
|
|
132
|
+
*/
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @type {(packageGet: package_.Get) =>
|
|
136
|
+
* (packageId: string) =>
|
|
137
|
+
* (local: string) =>
|
|
138
|
+
* (path: string) =>
|
|
139
|
+
* Result
|
|
140
|
+
* }
|
|
141
|
+
*/
|
|
142
|
+
const parseAndFind = packageGet => packageId => local => path => {
|
|
143
|
+
const currentPack = packageGet(packageId)
|
|
144
|
+
if (currentPack === undefined) { return undefined }
|
|
145
|
+
const p = parse(packageId)(currentPack.dependency)(local)(path)
|
|
146
|
+
if (p === undefined) { return undefined }
|
|
147
|
+
const pack = packageGet(p.packageId)
|
|
148
|
+
if (pack === undefined) { return undefined }
|
|
149
|
+
/** @type {(file: string) => Result } */
|
|
150
|
+
const tryFile = file => {
|
|
151
|
+
const source = pack.file(file)
|
|
152
|
+
return source === undefined ? undefined : { package: p.packageId, file, source }
|
|
153
|
+
}
|
|
154
|
+
const file = p.items.join('/')
|
|
155
|
+
const indexJs = list.join('/')(list.concat(p.items)(['index.js']))
|
|
156
|
+
const fileList = p.dir || list.isEmpty(p.items) ? [indexJs] : [file, `${file}.js`, indexJs]
|
|
157
|
+
return list.first(undefined)(list.filterMap(tryFile)(fileList))
|
|
158
|
+
}
|
|
159
|
+
|
|
114
160
|
module.exports = {
|
|
115
161
|
/** @readonly */
|
|
116
162
|
parseLocal,
|
|
@@ -118,4 +164,6 @@ module.exports = {
|
|
|
118
164
|
parseGlobal,
|
|
119
165
|
/** @readonly */
|
|
120
166
|
parse,
|
|
167
|
+
/** @readonly */
|
|
168
|
+
parseAndFind,
|
|
121
169
|
}
|
package/commonjs/path/test.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
const _ = require('.')
|
|
2
|
+
const { todo } = require('../../dev')
|
|
2
3
|
const json = require('../../json')
|
|
3
4
|
const { identity } = require('../../types/function')
|
|
5
|
+
const object = require('../../types/object')
|
|
4
6
|
const { at } = require('../../types/object')
|
|
7
|
+
const package_ = require('../package')
|
|
5
8
|
|
|
6
9
|
/** @type {(g: json.Unknown|undefined) => string} */
|
|
7
10
|
const stringify = g => {
|
|
@@ -51,15 +54,101 @@ const stringify = g => {
|
|
|
51
54
|
if (_.parseGlobal(d => at(d)({ b: 'x' }))(false)(['d']) !== undefined) { throw 'error' }
|
|
52
55
|
{
|
|
53
56
|
const result = stringify(_.parseGlobal(d => at(d)({ b: 'x' }))(false)(['b']))
|
|
54
|
-
if (result !== '
|
|
57
|
+
if (result !== '{"packageId":"x","items":[],"dir":false}') { throw result }
|
|
55
58
|
}
|
|
56
59
|
if (_.parseGlobal(d => at(d)({ 'b/r': 'x' }))(false)(['b']) !== undefined) { throw 'error' }
|
|
57
60
|
{
|
|
58
61
|
const result = stringify(_.parseGlobal(d => at(d)({ 'b/r': 'x' }))(false)(['b', 'r']))
|
|
59
|
-
if (result !== '
|
|
62
|
+
if (result !== '{"packageId":"x","items":[],"dir":false}') { throw result }
|
|
60
63
|
}
|
|
61
64
|
{
|
|
62
65
|
const result = stringify(_.parseGlobal(d => at(d)({ 'b/r': 'x' }))(false)(['b', 'r', 'd', 't']))
|
|
63
|
-
if (result !== '
|
|
66
|
+
if (result !== '{"packageId":"x","items":["d","t"],"dir":false}') { throw result }
|
|
64
67
|
}
|
|
68
|
+
{
|
|
69
|
+
const result = stringify(_.parseGlobal(d => at(d)({ 'b/r': 'x' }))(true)(['b', 'r', 'd', 't']))
|
|
70
|
+
if (result !== '{"packageId":"x","items":["d","t"],"dir":true}') { throw result }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
/** @type {object.Map<package_.Package>} */
|
|
76
|
+
const packages = {
|
|
77
|
+
'': {
|
|
78
|
+
dependency: () => todo(),
|
|
79
|
+
file: path => at(path)({ 'a/c': 'return "a/c"' }),
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const result = stringify(_.parseAndFind(p => at(p)(packages))('')('a/b')('../c'))
|
|
83
|
+
if (result !== '{"package":"","file":"a/c","source":"return \\"a/c\\""}') { throw result }
|
|
65
84
|
}
|
|
85
|
+
|
|
86
|
+
{
|
|
87
|
+
/** @type {object.Map<package_.Package>} */
|
|
88
|
+
const packages = {
|
|
89
|
+
'': {
|
|
90
|
+
dependency: x => {
|
|
91
|
+
const path = `node_modules/${x}`
|
|
92
|
+
return at(path)(packages) !== undefined ? path : undefined
|
|
93
|
+
},
|
|
94
|
+
file: todo
|
|
95
|
+
},
|
|
96
|
+
'node_modules/z': {
|
|
97
|
+
dependency: () => todo(),
|
|
98
|
+
file: path => at(path)({ 'a/c/index.js': 'return "a/c"' }),
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const result = stringify(_.parseAndFind(p => at(p)(packages))('')('a/b')('z/a/c'))
|
|
102
|
+
if (result !== '{"package":"node_modules/z","file":"a/c/index.js","source":"return \\"a/c\\""}') { throw result }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
{
|
|
106
|
+
/** @type {object.Map<package_.Package>} */
|
|
107
|
+
const packages = {
|
|
108
|
+
'': {
|
|
109
|
+
dependency: x => {
|
|
110
|
+
const path = `node_modules/${x}`
|
|
111
|
+
return at(path)(packages) !== undefined ? path : undefined
|
|
112
|
+
},
|
|
113
|
+
file: todo
|
|
114
|
+
},
|
|
115
|
+
'node_modules/z/a': {
|
|
116
|
+
dependency: () => todo(),
|
|
117
|
+
file: path => at(path)({
|
|
118
|
+
'c/index.js': 'return "c/index.js"',
|
|
119
|
+
'c.js': 'return "c.js"'
|
|
120
|
+
}),
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
{
|
|
124
|
+
const result = stringify(_.parseAndFind(p => at(p)(packages))('')('a/b')('z/a/c'))
|
|
125
|
+
if (result !== '{"package":"node_modules/z/a","file":"c.js","source":"return \\"c.js\\""}') { throw result }
|
|
126
|
+
}
|
|
127
|
+
{
|
|
128
|
+
const result = stringify(_.parseAndFind(p => at(p)(packages))('')('a/b')('z/a/c/'))
|
|
129
|
+
if (result !== '{"package":"node_modules/z/a","file":"c/index.js","source":"return \\"c/index.js\\""}') { throw result }
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
{
|
|
134
|
+
/** @type {object.Map<package_.Package>} */
|
|
135
|
+
const packages = {
|
|
136
|
+
'': {
|
|
137
|
+
dependency: x => {
|
|
138
|
+
const path = `node_modules/${x}`
|
|
139
|
+
return at(path)(packages) !== undefined ? path : undefined
|
|
140
|
+
},
|
|
141
|
+
file: todo
|
|
142
|
+
},
|
|
143
|
+
'node_modules/z/a/c': {
|
|
144
|
+
dependency: () => todo(),
|
|
145
|
+
file: path => at(path)({
|
|
146
|
+
'': 'throw',
|
|
147
|
+
'.js': 'throw',
|
|
148
|
+
'index.js': 'return "a/c"'
|
|
149
|
+
}),
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const result = stringify(_.parseAndFind(p => at(p)(packages))('')('a/b')('z/a/c'))
|
|
153
|
+
if (result !== '{"package":"node_modules/z/a/c","file":"index.js","source":"return \\"a/c\\""}') { throw result }
|
|
154
|
+
}
|
package/package.json
CHANGED
package/test.js
CHANGED
|
@@ -7,6 +7,7 @@ require('./types/object/test')
|
|
|
7
7
|
require('./io/commonjs/test')
|
|
8
8
|
require('./commonjs/package/dependencies/test')
|
|
9
9
|
require('./commonjs/package/test')
|
|
10
|
+
require('./commonjs/path/test')
|
|
10
11
|
|
|
11
12
|
/** @type {() => never} */
|
|
12
13
|
const assert = () => { throw 'assert' }
|
|
@@ -100,12 +101,12 @@ const assert_if = c => { if (c) { throw 'assert_if' } }
|
|
|
100
101
|
//const c = o['__defineGetter__']
|
|
101
102
|
//const c = o['__defineSetter__']
|
|
102
103
|
//const c = o['__lookupGetter__']
|
|
103
|
-
//const c = o['__lookupSetter__']
|
|
104
|
-
//const c = o['hasOwnProperty']
|
|
104
|
+
//const c = o['__lookupSetter__']
|
|
105
|
+
//const c = o['hasOwnProperty']
|
|
105
106
|
//const c = o['isPrototypeOf']
|
|
106
107
|
//const c = o['propertyIsEnumerable']
|
|
107
108
|
//const c = o['toString']
|
|
108
|
-
const c = o['valueOf']
|
|
109
|
+
const c = o['valueOf']
|
|
109
110
|
//console.log(c)
|
|
110
111
|
}
|
|
111
112
|
|
package/types/list/index.js
CHANGED
|
@@ -199,6 +199,9 @@ const some = input => find
|
|
|
199
199
|
(/** @type {(_: boolean) => boolean} */(identity))
|
|
200
200
|
(input)
|
|
201
201
|
|
|
202
|
+
/** @type {<T>(input: List<T>) => boolean} */
|
|
203
|
+
const isEmpty = input => !some(map(() => true)(input))
|
|
204
|
+
|
|
202
205
|
/** @type {(input: List<boolean>) => boolean} */
|
|
203
206
|
const every = input => !some(map(logicalNot)(input))
|
|
204
207
|
|
|
@@ -336,6 +339,8 @@ module.exports = {
|
|
|
336
339
|
/** @readonly */
|
|
337
340
|
every,
|
|
338
341
|
/** @readonly */
|
|
342
|
+
isEmpty,
|
|
343
|
+
/** @readonly */
|
|
339
344
|
includes,
|
|
340
345
|
/** @readonly */
|
|
341
346
|
countdown,
|
package/types/list/test.js
CHANGED
|
@@ -214,6 +214,16 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
|
|
|
214
214
|
if (result !== 12) { throw result }
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
{
|
|
218
|
+
const result = _.isEmpty(() => [])
|
|
219
|
+
if (result !== true) { throw result }
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
{
|
|
223
|
+
const result = _.isEmpty(() => [2])
|
|
224
|
+
if (result !== false) { throw result }
|
|
225
|
+
}
|
|
226
|
+
|
|
217
227
|
// stress tests
|
|
218
228
|
|
|
219
229
|
const stress = () => {
|
|
@@ -319,7 +329,7 @@ const stress = () => {
|
|
|
319
329
|
}
|
|
320
330
|
}
|
|
321
331
|
|
|
322
|
-
stress()
|
|
332
|
+
// stress()
|
|
323
333
|
|
|
324
334
|
module.exports = {
|
|
325
335
|
|