jostraca 0.4.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 (54) hide show
  1. package/dist/cmp/Content.d.ts +2 -0
  2. package/dist/cmp/Content.js +12 -0
  3. package/dist/cmp/Content.js.map +1 -0
  4. package/dist/cmp/Copy.d.ts +2 -0
  5. package/dist/cmp/Copy.js +13 -0
  6. package/dist/cmp/Copy.js.map +1 -0
  7. package/dist/cmp/File.d.ts +2 -0
  8. package/dist/cmp/File.js +13 -0
  9. package/dist/cmp/File.js.map +1 -0
  10. package/dist/cmp/Folder.d.ts +2 -0
  11. package/dist/cmp/Folder.js +12 -0
  12. package/dist/cmp/Folder.js.map +1 -0
  13. package/dist/cmp/Project.d.ts +2 -0
  14. package/dist/cmp/Project.js +13 -0
  15. package/dist/cmp/Project.js.map +1 -0
  16. package/dist/jostraca.d.ts +10 -34
  17. package/dist/jostraca.js +103 -294
  18. package/dist/jostraca.js.map +1 -1
  19. package/dist/op/ContentOp.d.ts +6 -0
  20. package/dist/op/ContentOp.js +12 -0
  21. package/dist/op/ContentOp.js.map +1 -0
  22. package/dist/op/CopyOp.d.ts +6 -0
  23. package/dist/op/CopyOp.js +188 -0
  24. package/dist/op/CopyOp.js.map +1 -0
  25. package/dist/op/FileOp.d.ts +6 -0
  26. package/dist/op/FileOp.js +43 -0
  27. package/dist/op/FileOp.js.map +1 -0
  28. package/dist/op/FolderOp.d.ts +6 -0
  29. package/dist/op/FolderOp.js +23 -0
  30. package/dist/op/FolderOp.js.map +1 -0
  31. package/dist/op/NoneOp.d.ts +6 -0
  32. package/dist/op/NoneOp.js +9 -0
  33. package/dist/op/NoneOp.js.map +1 -0
  34. package/dist/op/ProjectOp.d.ts +6 -0
  35. package/dist/op/ProjectOp.js +24 -0
  36. package/dist/op/ProjectOp.js.map +1 -0
  37. package/dist/tsconfig.tsbuildinfo +1 -0
  38. package/dist/utility.d.ts +44 -0
  39. package/dist/utility.js +213 -0
  40. package/dist/utility.js.map +1 -0
  41. package/package.json +4 -4
  42. package/src/cmp/Content.ts +19 -0
  43. package/src/cmp/Copy.ts +21 -0
  44. package/src/cmp/File.ts +21 -0
  45. package/src/cmp/Folder.ts +21 -0
  46. package/src/cmp/Project.ts +22 -0
  47. package/src/jostraca.ts +118 -380
  48. package/src/op/ContentOp.ts +18 -0
  49. package/src/op/CopyOp.ts +229 -0
  50. package/src/op/FileOp.ts +58 -0
  51. package/src/op/FolderOp.ts +31 -0
  52. package/src/op/NoneOp.ts +14 -0
  53. package/src/op/ProjectOp.ts +33 -0
  54. package/src/utility.ts +306 -0
@@ -0,0 +1,229 @@
1
+
2
+ import Path from 'node:path'
3
+
4
+ import type { Node } from '../jostraca'
5
+
6
+ import { getx } from '../jostraca'
7
+
8
+ import { FileOp } from './FileOp'
9
+
10
+
11
+ const CopyOp = {
12
+
13
+ before(node: Node, ctx$: any, buildctx: any) {
14
+ const fs = buildctx.fs
15
+
16
+ // TODO: do these need null checks here?
17
+ const name = node.name as string
18
+ const from = node.from as string
19
+
20
+ const fromStat = fs.statSync(from)
21
+
22
+ if (fromStat.isFile()) {
23
+ FileOp.before(node, ctx$, buildctx)
24
+ const topath = buildctx.current.file.path
25
+ const state = {
26
+ fileCount: 0,
27
+ folderCount: 0,
28
+ tmCount: 0,
29
+ ctx$,
30
+ buildctx,
31
+ }
32
+ const spec = { name, frompath: from, topath }
33
+
34
+ let content = processTemplate(state, fs.readFileSync(from).toString(), spec)
35
+
36
+ buildctx.current.file.content.push(content)
37
+ node.after = node.after || {}
38
+ node.after.kind = 'file'
39
+ }
40
+
41
+ else if (fromStat.isDirectory()) {
42
+ if (null != from && '' != from) {
43
+ node.after = node.after || {}
44
+ node.after.kind = 'copy'
45
+ }
46
+ }
47
+
48
+ else {
49
+ throw new Error('Unable to process file: ' + from)
50
+ }
51
+ },
52
+
53
+
54
+ after(node: Node, ctx$: any, buildctx: any) {
55
+ const info = buildctx.info
56
+ const kind = node.after.kind
57
+
58
+ const frompath = node.from as string
59
+ const topath = buildctx.current.folder.path.join('/')
60
+
61
+ let exclude = node.exclude
62
+ if (info && true === exclude) {
63
+ return
64
+ }
65
+
66
+ if ('file' === kind) {
67
+ FileOp.after(node, ctx$, buildctx)
68
+ }
69
+ else if ('copy' === kind) {
70
+ const state = {
71
+ fileCount: 0,
72
+ folderCount: 0,
73
+ tmCount: 0,
74
+ ctx$,
75
+ buildctx,
76
+ }
77
+
78
+ // TODO: node.path is wrong
79
+ // change prop.name to prop.to and account for subfolders
80
+
81
+ walk(state, node.path, frompath, topath)
82
+ }
83
+ else {
84
+ throw new Error('Unknown kind=' + kind + ' for file: ' + frompath)
85
+ }
86
+ },
87
+
88
+ }
89
+
90
+
91
+ function walk(state: any, nodepath: string[], from: string, to: string) {
92
+ const buildctx = state.buildctx
93
+ const fs = buildctx.fs
94
+ const entries = fs.readdirSync(from)
95
+
96
+ for (let name of entries) {
97
+ const frompath = Path.join(from, name)
98
+ const topath = Path.join(to, name)
99
+ const stat = fs.statSync(frompath)
100
+
101
+ if (stat.isDirectory()) {
102
+ state.folderCount++
103
+ walk(state, nodepath.concat(name), frompath, topath)
104
+ }
105
+ else if (isTemplate(name)) {
106
+ if (excludeFile(state, nodepath, name, topath)) { continue }
107
+ const src = fs.readFileSync(frompath, 'utf8')
108
+ const out = genTemplate(state, src, { name, frompath, topath })
109
+ writeFileSync(buildctx, topath, out)
110
+ state.fileCount++
111
+ state.tmCount++
112
+ }
113
+ else {
114
+ if (excludeFile(state, nodepath, name, topath)) { continue }
115
+ copyFileSync(buildctx, frompath, topath)
116
+ state.fileCount++
117
+ }
118
+ }
119
+ }
120
+
121
+
122
+ function excludeFile(state: any, nodepath: string[], name: string, frompath: string) {
123
+ const { fs, info } = state.buildctx
124
+ let exclude = false
125
+
126
+ // NOT Path.sep - needs to be canonical
127
+ const rpath = nodepath.concat(name).join('/')
128
+
129
+ if (info) {
130
+ exclude = info.exclude.includes(rpath)
131
+ let stat, timedelta
132
+ if (!exclude) {
133
+ stat = fs.statSync(frompath, { throwIfNoEntry: false })
134
+ if (stat) {
135
+ timedelta = stat.mtimeMs - info.last
136
+ if (stat && (timedelta > 0 && timedelta < stat.mtimeMs)) {
137
+ exclude = true
138
+ }
139
+ }
140
+ }
141
+
142
+ // if ('sdk.js' === name) {
143
+ // console.log('COPYSTAT', rpath, frompath,
144
+ // timedelta,
145
+ // info.exclude.includes(rpath),
146
+ // stat?.mtimeMs - info.last,
147
+ // stat?.mtimeMs, info.last, exclude)
148
+ // }
149
+ }
150
+
151
+ if (exclude && info && !info.exclude.includes(rpath)) {
152
+ // NOT Path.sep - has to be canonical
153
+ info.exclude.push(rpath)
154
+ }
155
+
156
+ // console.log('COPY-EXCLUDE', rpath, exclude)
157
+ return exclude
158
+ }
159
+
160
+
161
+ function writeFileSync(buildctx: any, path: string, content: string) {
162
+ // console.log('WF', path)
163
+ const fs = buildctx.fs
164
+ // TODO: check excludes
165
+ fs.mkdirSync(Path.dirname(path), { recursive: true })
166
+ fs.writeFileSync(path, content, 'utf8')
167
+ }
168
+
169
+
170
+ function copyFileSync(buildctx: any, frompath: string, topath: string) {
171
+ const fs = buildctx.fs
172
+ // TODO: check excludes
173
+ fs.mkdirSync(Path.dirname(topath), { recursive: true })
174
+ fs.copyFileSync(frompath, topath)
175
+ }
176
+
177
+
178
+ function processTemplate(
179
+ state: any,
180
+ src: any,
181
+ spec: { name: string, frompath: string, topath: string }) {
182
+ if (isTemplate(spec.name)) {
183
+ return genTemplate(state, src, spec)
184
+ }
185
+ return src
186
+ }
187
+
188
+ function isTemplate(name: string) {
189
+ // TODO: need a better way; alsp should be configurable
190
+ return !name.match(/\.(gif|jpe?g|png|ico|bmp|tiff)$/i)
191
+ }
192
+
193
+ // NOTE: $$foo.bar$$ format used as explicit start and end markers mean regex can be used
194
+ // unambiguously ($fooa would not match `foo`)
195
+ function genTemplate(
196
+ state: any,
197
+ src: any,
198
+ spec: { name: string, frompath: string, topath: string }) {
199
+
200
+ let model = state.ctx$.model // { foo: 'FOO', bar: 'BAR' }
201
+ let out = ''
202
+ let remain = src
203
+ let nextm = true
204
+ while (nextm) {
205
+ let m = remain.match(/\$\$([^$]+)\$\$/)
206
+ if (m) {
207
+ let ref = m[1]
208
+ out += remain.substring(0, m.index)
209
+ let insert = getx(model, ref)
210
+ if (null == insert) {
211
+ out += '$$' + ref + '$$'
212
+ remain = remain.substring(m.index + 4 + ref.length)
213
+ }
214
+ else {
215
+ out += insert
216
+ remain = remain.substring(m.index + 4 + ref.length)
217
+ }
218
+ }
219
+ else {
220
+ out += remain
221
+ nextm = false
222
+ }
223
+ }
224
+ return out
225
+ }
226
+
227
+ export {
228
+ CopyOp
229
+ }
@@ -0,0 +1,58 @@
1
+
2
+ import Path from 'node:path'
3
+
4
+ import type { Node } from '../jostraca'
5
+
6
+
7
+ const FileOp = {
8
+
9
+ before(node: Node, _ctx$: any, buildctx: any) {
10
+ const cfile: any = buildctx.current.file = node
11
+ cfile.filepath = buildctx.current.folder.path.join('/') + '/' + node.name
12
+ cfile.content = []
13
+ },
14
+
15
+
16
+ after(node: Node, _ctx$: any, buildctx: any) {
17
+ // console.log('FB-INFO', buildctx.info)
18
+
19
+ const { fs, info, current } = buildctx
20
+ const cfile = current.file
21
+ const content = cfile.content.join('')
22
+ const rpath = cfile.path.join('/') // NOT Path.sep - needs to be canonical
23
+ let exclude = node.exclude
24
+
25
+ // console.log('FILE-a exclude', rpath, exclude, !!info)
26
+
27
+ if (info && null == exclude) {
28
+ exclude = info.exclude.includes(rpath)
29
+ if (!exclude) {
30
+ const stat = fs.statSync(cfile.filepath, { throwIfNoEntry: false })
31
+ if (stat) {
32
+ let timedelta = stat.mtimeMs - info.last
33
+ if ((timedelta > 0 && timedelta < stat.mtimeMs)) {
34
+ exclude = true
35
+ }
36
+ // console.log('STAT', rpath, timedelta, exclude, stat?.mtimeMs, info.last)
37
+ }
38
+ }
39
+ }
40
+
41
+ // console.log('FILE-a write', rpath, exclude) // , content.substring(0, 111))
42
+
43
+ if (!exclude) {
44
+ fs.writeFileSync(cfile.filepath, content)
45
+ }
46
+ else {
47
+ if (!info.exclude.includes(rpath)) {
48
+ info.exclude.push(rpath)
49
+ }
50
+ }
51
+ },
52
+
53
+ }
54
+
55
+
56
+ export {
57
+ FileOp
58
+ }
@@ -0,0 +1,31 @@
1
+
2
+ import Path from 'node:path'
3
+
4
+ import type { Node } from '../jostraca'
5
+
6
+
7
+ const FolderOp = {
8
+
9
+ before(node: Node, _ctx$: any, buildctx: any) {
10
+ const cfolder = buildctx.current.folder = (buildctx.current.folder || {})
11
+
12
+ cfolder.node = node
13
+ cfolder.path = (cfolder.path || [buildctx.current.folder.parent])
14
+ cfolder.path.push(node.name)
15
+
16
+ let fullpath = cfolder.path.join(Path.sep)
17
+ buildctx.fs.mkdirSync(fullpath, { recursive: true })
18
+ },
19
+
20
+
21
+ after(_node: Node, _ctx$: any, buildctx: any) {
22
+ const cfolder = buildctx.current.folder
23
+ cfolder.path.length = cfolder.path.length - 1
24
+ },
25
+
26
+ }
27
+
28
+
29
+ export {
30
+ FolderOp
31
+ }
@@ -0,0 +1,14 @@
1
+
2
+
3
+ import type { Node } from '../jostraca'
4
+
5
+
6
+ const NoneOp = {
7
+ before(node: Node, _ctx$: any, buildctx: any) { },
8
+ after(_node: Node, _ctx$: any, buildctx: any) { },
9
+ }
10
+
11
+
12
+ export {
13
+ NoneOp
14
+ }
@@ -0,0 +1,33 @@
1
+
2
+ import Path from 'node:path'
3
+
4
+ import type { Node } from '../jostraca'
5
+
6
+
7
+ const ProjectOp = {
8
+
9
+ before(node: Node, ctx$: any, buildctx: any) {
10
+ // console.log('PROJECT-B', node.folder, ctx$.folder)
11
+
12
+ node.folder = null == node.folder || '' === node.folder ? '.' : node.folder
13
+ node.folder = Path.isAbsolute(node.folder) ? node.folder : Path.join(ctx$.folder, node.folder)
14
+
15
+ // console.log('PROJECT-B folder', node.folder)
16
+
17
+ buildctx.current.project = { node }
18
+ buildctx.current.folder = {
19
+ node,
20
+ path: node.folder.split(Path.sep),
21
+ }
22
+
23
+ buildctx.fs.mkdirSync(node.folder, { recursive: true })
24
+ },
25
+
26
+ after(_node: Node, _ctx$: any, _buildctx: any) { },
27
+
28
+ }
29
+
30
+
31
+ export {
32
+ ProjectOp
33
+ }
package/src/utility.ts ADDED
@@ -0,0 +1,306 @@
1
+ /* Copyright (c) 2024 Richard Rodger, MIT License */
2
+
3
+
4
+ type JostracaOptions = {
5
+ folder?: string
6
+ fs?: any
7
+ meta?: any
8
+ }
9
+
10
+
11
+ type Node = {
12
+ kind: string
13
+ children?: Node[]
14
+ name?: string
15
+ path: string[]
16
+ from?: string
17
+ content?: any[]
18
+ folder?: string
19
+ after?: any
20
+ exclude?: boolean
21
+ }
22
+
23
+
24
+ type OpStep = (node: Node, ctx$: any, buildctx: any) => void
25
+
26
+ type OpDef = {
27
+ before: OpStep,
28
+ after: OpStep,
29
+ }
30
+
31
+
32
+ type Component = (props: any, children?: any) => void
33
+
34
+
35
+
36
+
37
+ function each(subject?: any, apply?: any) {
38
+ if (null == apply) {
39
+ let out = []
40
+ if (Array.isArray(subject)) {
41
+ for (let fn of subject) {
42
+ out.push('function' === typeof fn ? fn() : fn)
43
+ }
44
+ return out.sort()
45
+ }
46
+ else if (null == subject || 'object' !== typeof subject) {
47
+ return []
48
+ }
49
+ }
50
+ else if (Array.isArray(subject)) {
51
+ return subject.map(apply)
52
+ }
53
+
54
+ if (null == subject || 'object' !== typeof subject) {
55
+ return []
56
+ }
57
+
58
+ const entries: any = Object.entries(subject).map((n: any[], _: any) =>
59
+ (_ = typeof n[1],
60
+ (null != n[1] && 'object' === _) ? (n[1].key$ = n[0]) :
61
+ (n[1] = { name: n[0], key$: n[0], val$: n[1] }), n))
62
+
63
+ if (1 < entries.length) {
64
+ if (entries[0] && entries[0][1] && 'string' === typeof entries[0][1].name) {
65
+ entries.sort((a: any, b: any) =>
66
+ a[1].name < b[1].name ? -1 : b[1].name < a[1].name ? 1 : 0)
67
+ }
68
+ else if (entries[0] && entries[0][1] && 'string' === typeof entries[0][1].key$) {
69
+ entries.sort((a: any, b: any) =>
70
+ a[1].key$ < b[1].key$ ? -1 : b[1].key$ < a[1].key$ ? 1 : 0)
71
+ }
72
+ }
73
+
74
+ apply = 'function' === typeof apply ? apply : (x: any) => x
75
+
76
+ return entries.map((n: any, ...args: any[]) =>
77
+ apply(n[1], n[0], ...args))
78
+ }
79
+
80
+
81
+
82
+ function select(key: any, map: Record<string, Function>) {
83
+ const fn = map && map[key]
84
+ return fn ? fn() : undefined
85
+ }
86
+
87
+
88
+
89
+ function getx(root: any, path: string | string[]): any {
90
+ path = ('string' === typeof path ? path.split(/[.\s\r\n\t]/) : path).filter(part => '' != part)
91
+ let node = root
92
+ let parents = []
93
+
94
+ partloop:
95
+ for (let i = 0; i < path.length && null != node; i++) {
96
+ let part = String(path[i]).trim()
97
+
98
+ if ('*' === part) {
99
+ // console.log('STAR', each(node), path.slice(i + 1))
100
+ return getx(each(node), path.slice(i + 1))
101
+ }
102
+
103
+ let m = part.match(/^([^<=>~^?!]*)([<=>~^?!]+)(.*)$/)
104
+
105
+ if (m) {
106
+ part = m[1]
107
+ let op = m[2]
108
+ let arg: any = m[3]
109
+
110
+ let val = '' === part ? node : node[part]
111
+
112
+ const argtype = typeof arg
113
+ arg =
114
+ 'true' === arg ? true :
115
+ 'false' === arg ? false :
116
+ 'string' === argtype ?
117
+ (arg.match(/^"[^"]+"$/) ? arg.substring(1, arg.length - 1) : arg) : arg
118
+
119
+ // console.log('GETX-M', val, part, op, arg)
120
+
121
+ if ('=' === op && 'null' === arg) {
122
+ parents.push(node)
123
+ node = {} // virtual node so that ^ works consistently
124
+ continue partloop
125
+ }
126
+ else if ('^' === op && '' === part && '' !== arg) {
127
+ node = parents[parents.length - Number(arg)]
128
+ continue partloop
129
+ }
130
+ else if ('?' === op[0]) {
131
+ // no property name
132
+ arg = (1 < op.length ? op.substring(1) : '') + arg
133
+
134
+ node = Array.isArray(val) ?
135
+ each(val).filter((n: any) => (
136
+ null != getx(n, arg))) :
137
+ each(val).filter((n: any) => (
138
+ null != getx(n, arg)))
139
+ .reduce((a: any, n: any) => (a[n.key$] = n, delete n.key$, a), {})
140
+
141
+ continue partloop
142
+ }
143
+
144
+ if (null == val) return undefined
145
+
146
+ // const valtype = typeof val
147
+
148
+ val = Array.isArray(val) ? val.length :
149
+ 'object' === typeof val ? Object.keys(val).filter(k => !k.includes('$')).length :
150
+ val
151
+
152
+ switch (op) {
153
+ case '<':
154
+ if (!(val < arg)) return undefined
155
+ break
156
+ case '<=':
157
+ if (!(val <= arg)) return undefined
158
+ break
159
+ case '>':
160
+ if (!(val > arg)) return undefined
161
+ break
162
+ case '>=':
163
+ if (!(val >= arg)) return undefined
164
+ break
165
+ case '=':
166
+ if (!(val == arg)) return undefined
167
+ break
168
+ case '==':
169
+ if (!(val === arg)) return undefined
170
+ break
171
+ case '!=':
172
+ if (!(val != arg)) return undefined
173
+ break
174
+ case '~':
175
+ if (!(String(val).match(RegExp(arg)))) return undefined
176
+ break
177
+ case '^':
178
+ node = parents[parents.length - Number(arg)]
179
+ continue partloop
180
+ default:
181
+ return undefined
182
+ }
183
+ }
184
+
185
+ parents.push(node)
186
+ node = '' === part ? node : node[part]
187
+ }
188
+ return node
189
+ }
190
+
191
+
192
+ function get(root: any, path: string | string[]): any {
193
+ path = 'string' === typeof path ? path.split('.') : path
194
+ let node = root
195
+ for (let i = 0; i < path.length && null != node; i++) {
196
+ node = node[path[i]]
197
+ }
198
+ return node
199
+ }
200
+
201
+
202
+ function camelify(input: any[] | string) {
203
+ let parts = 'string' == typeof input ? input.split('-') : input.map(n => '' + n)
204
+ return parts
205
+ .map((p: string) => ('' === p ? '' : (p[0].toUpperCase() + p.substring(1))))
206
+ .join('')
207
+ }
208
+
209
+
210
+ function kebabify(input: any[] | string) {
211
+ let parts = 'string' == typeof input ? input.split(/([A-Z])/) : input.map(n => '' + n)
212
+ return parts
213
+ .filter((p: string) => '' !== p)
214
+ .reduce((a: any[], n: string, i: number) =>
215
+ ((0 === i % 2 ? a.push(n.toLowerCase()) : a[(i / 2) | 0] += n), a), [])
216
+ .join('-')
217
+ }
218
+
219
+
220
+ function snakify(input: any[] | string) {
221
+ let parts = 'string' == typeof input ? input.split(/([A-Z])/) : input.map(n => '' + n)
222
+ return parts
223
+ .filter((p: string) => '' !== p)
224
+ .reduce((a: any[], n: string, i: number) =>
225
+ ((0 === i % 2 ? a.push(n.toLowerCase()) : a[(i / 2) | 0] += n), a), [])
226
+ .join('_')
227
+ }
228
+
229
+
230
+ function names(base: any, name: string, prop = 'name') {
231
+ base.name$ = name
232
+ base[prop.toLowerCase()] = name.toLowerCase()
233
+ base[camelify(prop)] = camelify(name)
234
+ base[snakify(prop)] = snakify(name)
235
+ base[kebabify(prop)] = kebabify(name)
236
+ base[prop.toUpperCase()] = name.toUpperCase()
237
+ }
238
+
239
+
240
+
241
+ // Map child objects to new child objects
242
+ function cmap(o: any, p: any) {
243
+ return Object
244
+ .entries(o)
245
+ .reduce((r: any, n: any, _: any) => (_ = Object
246
+ .entries(p)
247
+ .reduce((s: any, m: any) => (cmap.FILTER === s ? s : (s[m[0]] = (
248
+ // transfom(val,key,current,parentkey,parent)
249
+ 'function' === typeof m[1] ? m[1](n[1][m[0]], {
250
+ skey: m[0], self: n[1], key: n[0], parent: o
251
+ }) : m[1]
252
+ ), (cmap.FILTER === s[m[0]] ? cmap.FILTER : s))), {})
253
+ , (cmap.FILTER === _ ? 0 : r[n[0]] = _), r), {})
254
+ }
255
+
256
+ cmap.COPY = (x: any) => x
257
+ // keep self if x is truthy, or function returning truthy-new-value or [truthy,new-value]
258
+ cmap.FILTER = (x: any) => 'function' === typeof x ? ((y: any, p: any, _: any) =>
259
+ (_ = x(y, p), Array.isArray(_) ? !_[0] ? _[1] : cmap.FILTER : _)) : (x ? x : cmap.FILTER)
260
+ cmap.KEY = (_: any, p: any) => p.key
261
+
262
+
263
+ // Map child objects to a list of child objects
264
+ function vmap(o: any, p: any) {
265
+ return Object
266
+ .entries(o)
267
+ .reduce((r: any, n: any, _: any) => (_ = Object
268
+ .entries(p)
269
+ .reduce((s: any, m: any) => (vmap.FILTER === s ? s : (s[m[0]] = (
270
+ // transfom(val,key,current,parentkey,parent)
271
+ // 'function' === typeof m[1] ? m[1](n[1][m[0]], m[0], n[1], n[0], o) : m[1]
272
+ 'function' === typeof m[1] ? m[1](n[1][m[0]], {
273
+ skey: m[0], self: n[1], key: n[0], parent: o
274
+ }) : m[1]
275
+ ), (vmap.FILTER === s[m[0]] ? vmap.FILTER : s))), {})
276
+ , (vmap.FILTER === _ ? 0 : r.push(_)), r), [])
277
+
278
+ }
279
+ vmap.COPY = (x: any) => x
280
+ vmap.FILTER = (x: any) => 'function' === typeof x ? ((y: any, p: any, _: any) =>
281
+ (_ = x(y, p), Array.isArray(_) ? !_[0] ? _[1] : vmap.FILTER : _)) : (x ? x : vmap.FILTER)
282
+ vmap.KEY = (_: any, p: any) => p.key
283
+
284
+
285
+
286
+ export type {
287
+ JostracaOptions,
288
+ Node,
289
+ OpStep,
290
+ OpDef,
291
+ Component,
292
+ }
293
+
294
+
295
+ export {
296
+ each,
297
+ select,
298
+ get,
299
+ getx,
300
+ camelify,
301
+ snakify,
302
+ kebabify,
303
+ cmap,
304
+ vmap,
305
+ names,
306
+ }