@voxgig/model 4.0.0 → 5.0.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 (45) hide show
  1. package/bin/voxgig-model +150 -31
  2. package/dist/{lib/build.d.ts → build.d.ts} +6 -5
  3. package/dist/{lib/build.js → build.js} +4 -3
  4. package/dist/build.js.map +1 -0
  5. package/dist/{lib/builder → builder}/local.js +13 -34
  6. package/dist/builder/local.js.map +1 -0
  7. package/dist/{lib/builder → builder}/model.js +5 -0
  8. package/dist/builder/model.js.map +1 -0
  9. package/dist/{lib/config.d.ts → config.d.ts} +4 -3
  10. package/dist/{lib/config.js → config.js} +6 -4
  11. package/dist/config.js.map +1 -0
  12. package/dist/model.d.ts +7 -6
  13. package/dist/model.js +33 -19
  14. package/dist/model.js.map +1 -1
  15. package/dist/tsconfig.tsbuildinfo +1 -0
  16. package/dist/{lib/types.d.ts → types.d.ts} +25 -3
  17. package/dist/types.js +4 -0
  18. package/dist/types.js.map +1 -0
  19. package/dist/{lib/watch.d.ts → watch.d.ts} +6 -19
  20. package/dist/{lib/watch.js → watch.js} +41 -16
  21. package/dist/watch.js.map +1 -0
  22. package/package.json +19 -20
  23. package/dist/lib/build.js.map +0 -1
  24. package/dist/lib/builder/local.js.map +0 -1
  25. package/dist/lib/builder/model.js.map +0 -1
  26. package/dist/lib/config.js.map +0 -1
  27. package/dist/lib/model-builder.d.ts +0 -0
  28. package/dist/lib/model-builder.js +0 -2
  29. package/dist/lib/model-builder.js.map +0 -1
  30. package/dist/lib/types.js +0 -3
  31. package/dist/lib/types.js.map +0 -1
  32. package/dist/lib/util.d.ts +0 -7
  33. package/dist/lib/util.js +0 -94
  34. package/dist/lib/util.js.map +0 -1
  35. package/dist/lib/watch.js.map +0 -1
  36. package/dist/model.min.js +0 -94
  37. package/lib/build.ts +0 -138
  38. package/lib/builder/local.ts +0 -130
  39. package/lib/builder/model.ts +0 -37
  40. package/lib/config.ts +0 -50
  41. package/lib/types.ts +0 -67
  42. package/lib/watch.ts +0 -301
  43. package/model.ts +0 -147
  44. /package/dist/{lib/builder → builder}/local.d.ts +0 -0
  45. /package/dist/{lib/builder → builder}/model.d.ts +0 -0
@@ -1,130 +0,0 @@
1
-
2
- import Path from 'path'
3
-
4
- import type { Build, Builder, BuildContext } from '../types'
5
-
6
-
7
- // Runs any builders local to the repo.
8
- const local_builder: Builder = async (build: Build, ctx: BuildContext) => {
9
- ctx.state.local = (ctx.state.local || {})
10
- let actionDefs = ctx.state.local.actionDefs
11
-
12
- if (null == actionDefs) {
13
- try {
14
- actionDefs = ctx.state.local.actionDefs = []
15
-
16
- // TODO: need to provide project root via build
17
- let root = Path.resolve(build.path, '..', '..')
18
-
19
-
20
- // TODO: build should do this
21
- let configbuild = build.use.config
22
-
23
- let config = configbuild.watch.last.build.model
24
-
25
- let builders = config.sys.model.builders
26
-
27
- // TODO: order by comma sep string
28
- // Load builders
29
- for (let name in builders) {
30
- let builder = builders[name]
31
- let action_path = Path.join(root, builder.load)
32
-
33
-
34
- // clear(action_path)
35
-
36
-
37
- let action = require(action_path)
38
-
39
- if (action instanceof Promise) {
40
- action = await action
41
- }
42
-
43
- const step = action.step || 'post'
44
-
45
- actionDefs.push({ name, builder, action, step })
46
- }
47
- }
48
- catch (e: any) {
49
- throw e
50
- }
51
- }
52
-
53
-
54
- if ('pre' === ctx.step) {
55
- try {
56
- let ok = true
57
- let brlog = []
58
-
59
- for (let actionDef of actionDefs) {
60
- if ('pre' === actionDef.step || 'all' === actionDef.step) {
61
- let br = await actionDef.action(build.model, build)
62
- ok = ok && null != br && br.ok
63
- brlog.push(br)
64
- }
65
- }
66
-
67
- return { ok: true, step: ctx.step, active: true }
68
- }
69
- catch (e: any) {
70
- throw e
71
- }
72
- }
73
-
74
- else if ('post' === ctx.step) {
75
- try {
76
- let ok = true
77
- let brlog = []
78
-
79
- for (let actionDef of actionDefs) {
80
- if ('post' === actionDef.step || 'all' === actionDef.step) {
81
- let br = await actionDef.action(build.model, build)
82
- ok = ok && null != br && br.ok
83
- brlog.push(br)
84
- }
85
- }
86
-
87
- return { ok: true, step: ctx.step, active: true }
88
- }
89
- catch (e: any) {
90
- throw e
91
- }
92
- }
93
-
94
- return { ok: false, why: 'bad-step', step: ctx.step, active: false }
95
- }
96
-
97
- /*
98
- // Adapted from https://github.com/sindresorhus/import-fresh - Thanks!
99
- function clear(path: string) {
100
- let filePath = require.resolve(path)
101
-
102
- if (require.cache[filePath]) {
103
- const children = require.cache[filePath].children.map(child => child.id)
104
-
105
- // Delete module from cache
106
- delete require.cache[filePath]
107
-
108
- for (const id of children) {
109
- clear(id)
110
- }
111
- }
112
-
113
-
114
- if (require.cache[filePath] && require.cache[filePath].parent) {
115
- let i = require.cache[filePath].parent.children.length
116
-
117
- while (i--) {
118
- if (require.cache[filePath].parent.children[i].id === filePath) {
119
- require.cache[filePath].parent.children.splice(i, 1)
120
- }
121
- }
122
- }
123
-
124
- }
125
- */
126
-
127
-
128
- export {
129
- local_builder
130
- }
@@ -1,37 +0,0 @@
1
-
2
- import Path from 'path'
3
-
4
- import { writeFile } from 'fs/promises'
5
-
6
- import type { Build, Builder, BuildContext } from '../types'
7
-
8
-
9
- // Builds the main model file, after unification.
10
- const model_builder: Builder = async (build: Build, ctx: BuildContext) => {
11
- if ('post' !== ctx.step) {
12
- return { ok: true, step: ctx.step, active: false }
13
- }
14
-
15
- try {
16
- let json = JSON.stringify(build.root.gen(), null, 2)
17
-
18
- let filename = Path.basename(build.path)
19
- let filenameparts = filename.match(/^(.*)\.[^.]+$/)
20
- if (filenameparts) {
21
- filename = filenameparts[1]
22
- }
23
-
24
- let file = build.opts.base + '/' + filename + '.json'
25
-
26
- await writeFile(file, json)
27
-
28
- return { ok: true, step: ctx.step, active: true }
29
- }
30
- catch (e: any) {
31
- throw e
32
- }
33
- }
34
-
35
- export {
36
- model_builder
37
- }
package/lib/config.ts DELETED
@@ -1,50 +0,0 @@
1
- /* Copyright © 2021-2024 Voxgig Ltd, MIT License. */
2
-
3
-
4
- import type { BuildResult, Spec } from './types'
5
-
6
- import { Watch } from './watch'
7
-
8
- import { model_builder } from './builder/model'
9
-
10
-
11
-
12
-
13
-
14
-
15
- class Config {
16
- build: any
17
- watch: Watch
18
-
19
- constructor(spec: Spec) {
20
- this.build = {
21
- src: spec.src,
22
- path: spec.path,
23
- base: spec.base,
24
- res: [
25
- ...(spec.res || [])
26
- ],
27
- require: spec.require
28
- }
29
-
30
- this.watch = new Watch(this.build)
31
- }
32
-
33
- async run(): Promise<BuildResult> {
34
- return this.watch.run(true, '<config>')
35
- }
36
-
37
- async start() {
38
- return this.watch.start()
39
- }
40
-
41
- async stop() {
42
- return this.watch.stop()
43
- }
44
- }
45
-
46
-
47
- export { Config, Spec }
48
-
49
-
50
-
package/lib/types.ts DELETED
@@ -1,67 +0,0 @@
1
-
2
-
3
-
4
- interface Build {
5
- id: string
6
- src: string
7
- base: string
8
- path: string
9
- root: any
10
- opts: { [key: string]: any }
11
- res: BuildAction[]
12
- spec: Spec
13
- model: any
14
- use: { [name: string]: any }
15
- err: any[]
16
- ctx: BuildContext
17
-
18
- run: () => Promise<BuildResult>
19
- }
20
-
21
-
22
- interface BuildResult {
23
- ok: boolean
24
- builder?: string
25
- path?: string
26
- build?: Build
27
- builders?: BuildResult[]
28
- step?: string
29
- err?: any[]
30
- }
31
-
32
- interface BuildAction {
33
- path: string
34
- build: Builder
35
- }
36
-
37
-
38
- interface BuildContext {
39
- step: 'pre' | 'post'
40
- state: Record<string, any>
41
- }
42
-
43
- type Builder = (
44
- build: Build,
45
- ctx: BuildContext,
46
- ) => Promise<BuildResult>
47
-
48
-
49
- interface Spec {
50
- src: string
51
- path?: string
52
- base?: string
53
- res?: BuildAction[]
54
- require?: any
55
- use?: { [name: string]: any }
56
- }
57
-
58
-
59
-
60
- export type {
61
- Build,
62
- BuildResult,
63
- BuildAction,
64
- Builder,
65
- BuildContext,
66
- Spec,
67
- }
package/lib/watch.ts DELETED
@@ -1,301 +0,0 @@
1
- /* Copyright © 2021-2024 Voxgig Ltd, MIT License. */
2
-
3
- import Path from 'node:path'
4
-
5
-
6
- import type { Build, BuildResult } from './types'
7
-
8
- import { makeBuild } from './build'
9
- import { FSWatcher } from 'chokidar'
10
-
11
- import { readFile, stat } from 'fs/promises'
12
-
13
-
14
- const print = console.log
15
- const warn = console.warn
16
-
17
-
18
- type Run = {
19
- canon: string
20
- path: string
21
- start: number
22
- end: number
23
- }
24
-
25
- type Canon = {
26
- path: string
27
- isFolder: boolean
28
- when: number
29
- }
30
-
31
-
32
- type ChangeItem = {
33
- path: string
34
- when: number
35
- }
36
-
37
- class Watch {
38
- fsw: FSWatcher
39
- spec: any
40
- last?: BuildResult
41
- lastChangeTime: number
42
- build: Build | undefined
43
- runq: Run[]
44
- doneq: Run[]
45
- canons: Canon[]
46
- lastrun: Run | undefined
47
- idle: number
48
- startTime: number
49
- running: boolean
50
- lastChange: ChangeItem
51
- lastTrigger: ChangeItem
52
-
53
- constructor(spec: any) {
54
- this.spec = spec
55
- this.fsw = new FSWatcher()
56
- this.lastChangeTime = 0
57
- this.runq = []
58
- this.doneq = []
59
- this.canons = []
60
- this.startTime = 0
61
- this.lastChange = { path: '', when: 0 }
62
- this.lastTrigger = { path: '', when: 0 }
63
- this.running = false
64
- this.lastrun = undefined
65
-
66
- this.idle = spec.idle || 111
67
-
68
- this.fsw.on('change', async (path: string) => {
69
- // console.log('CHANGE', Date.now() - this.startTime, path)
70
- this.handleChange(path)
71
- })
72
- }
73
-
74
-
75
- // Returns first BuildResult
76
- start() {
77
- this.startTime = Date.now()
78
- this.handleChange('<start>')
79
-
80
- // Check if there have been no recent changes, if so, run build.
81
- setInterval(() => {
82
- const start = this.startTime
83
- const now = Date.now()
84
- const idleDuration = now - this.lastChange.when
85
-
86
- // Only trigger a build if there was a actual change
87
- const trigger = this.lastChange.when !== this.lastTrigger.when &&
88
- this.lastChange.path !== this.lastTrigger.path
89
-
90
- // console.log('CHECK-A', {
91
- // tick: (now - start),
92
- // idleDuration,
93
- // trigger,
94
- // running: this.running,
95
- // path: this.lastChange.path
96
- // })
97
-
98
- if (trigger) {
99
-
100
- // Only add to build queue if we've been idle.
101
- // This allows external compilation outputting multiple files to complete fully.
102
- // IMPORTANT: always trigger a new build if there were changes *inside* a build period
103
- if (this.idle < idleDuration) {
104
- this.lastTrigger.path = this.lastChange.path
105
- this.lastTrigger.when = this.lastChange.when
106
-
107
- const path = this.lastChange.path
108
- const canon = this.canon(path)
109
-
110
- this.runq.push({
111
- canon,
112
- path,
113
- start: now,
114
- end: -1,
115
- })
116
-
117
- // Defer builds to the event loop to keep idle checking separate.
118
- setImmediate(this.drain.bind(this))
119
- }
120
- }
121
-
122
- }, (this.idle * 1.1 / 2) | 0)
123
- }
124
-
125
-
126
- // If path is inside a watched folder, return folder as canonical reference.
127
- canon(path: string) {
128
- for (const canon of this.canons) {
129
- if (canon.isFolder && path.startsWith(canon.path)) {
130
- return canon.path
131
- }
132
- }
133
- return path
134
- }
135
-
136
-
137
- handleChange(path: string) {
138
- // Record most recent (last) changed path and time
139
- this.lastChange.path = path
140
- this.lastChange.when = Date.now()
141
- }
142
-
143
-
144
- async drain() {
145
- // If already running, all items in queue will be drained from this.runq in the while loop
146
- if (this.running) {
147
- return
148
- }
149
-
150
- this.running = true
151
- let r: Run | undefined
152
-
153
- // While there are queued runs, run them sequentially
154
- while (r = this.runq.shift()) {
155
- // console.log('===DRAIN-RUN', this.runq.length, new Date(), r.start, r.canon)
156
-
157
- // TODO: collect results and errors!!!
158
- let br = await this.run(false, r.canon)
159
- // console.log('BR', br)
160
-
161
- r.end = Date.now()
162
- this.doneq.push(r)
163
- this.lastrun = r
164
-
165
- // console.log('===DRAIN-DONE', this.runq.length, new Date(), r.start, r.canon)
166
- }
167
- this.running = false
168
- }
169
-
170
-
171
- async add(path: string) {
172
- if (!Path.isAbsolute(path)) {
173
- path = Path.join(this.spec.require, path)
174
- }
175
-
176
- // Ignore if aleady added
177
- if (this.canons.find((c: Canon) => c.path === path)) {
178
- return
179
- }
180
-
181
- const fileStat = await stat(path)
182
- const canon: Canon = {
183
- path: path,
184
- isFolder: fileStat.isDirectory(),
185
- when: Date.now()
186
- }
187
-
188
- this.canons.push(canon)
189
-
190
- this.fsw.add(path)
191
-
192
- // console.log('ADD', canon)
193
- }
194
-
195
-
196
- async update(br: BuildResult) {
197
- let build = (br.build as Build)
198
-
199
- let files: string[] =
200
- Object.keys(build.root.deps).reduce((files: string[], target: any) => {
201
- files = files.concat(Object.keys(build.root.deps[target]))
202
- return files
203
- }, [build.path])
204
-
205
-
206
- // TODO: remove deleted files
207
- files.forEach(async (file: string) => {
208
- if ('string' === typeof (file) &&
209
- '' !== file &&
210
- build.opts.base !== file
211
- ) {
212
- await this.add(file)
213
- }
214
- })
215
-
216
- }
217
-
218
-
219
-
220
- async run(once?: boolean, trigger?: string): Promise<BuildResult> {
221
- // console.trace()
222
-
223
- this.lastChangeTime = Date.now()
224
- print('\n@voxgig/model =================', this.lastChangeTime, new Date(this.lastChangeTime))
225
- print('TRIGGER:', trigger, '\n')
226
-
227
- // TODO: build spec should not have src!
228
- let src = (await readFile(this.spec.path)).toString()
229
- this.spec.src = src
230
-
231
- this.build = this.build || makeBuild(this.spec)
232
-
233
- // TODO: better way to do this?
234
- this.build.src = src
235
-
236
- let br: BuildResult = await this.build.run()
237
-
238
- print('\nFILES:\n' + this.descDeps((br as any).build.root.deps) + '\n')
239
-
240
- if (br.ok) {
241
- print('TOP:', Object.keys(br?.build?.model).join(', '), '\n')
242
-
243
- if (!once) {
244
- // There may be new files.
245
- await this.update(br)
246
- }
247
- }
248
- else {
249
- warn('MODEL ERRORS: ' + br.err?.length)
250
- this.handleErrors(br)
251
- }
252
-
253
- this.last = br
254
-
255
- return br
256
- }
257
-
258
-
259
- async stop() {
260
- await this.fsw.close()
261
- }
262
-
263
-
264
- handleErrors(br: BuildResult) {
265
- if (br.err) {
266
- for (let be of br.err) {
267
- // TODO: print stack if not a model error
268
-
269
- if (be.isVal && be.msg) {
270
- warn(be.msg)
271
- }
272
- // else if (be.message) {
273
- // warn(be.message)
274
- // }
275
- else {
276
- warn(be)
277
- }
278
- }
279
- }
280
- }
281
-
282
- descDeps(deps: Record<string, Record<string, { tar: string }>>) {
283
- if (null == deps) {
284
- return ''
285
- }
286
-
287
- let desc = []
288
- for (let entryPath of Object.keys(deps)) {
289
- desc.push(' ' + entryPath)
290
- for (let depPath of Object.keys(deps[entryPath])) {
291
- desc.push(' ' + depPath)
292
- }
293
- }
294
- return desc.join('\n')
295
- }
296
- }
297
-
298
-
299
- export {
300
- Watch
301
- }