votive 0.0.8 → 0.0.9

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 CHANGED
@@ -7,12 +7,11 @@
7
7
 
8
8
  ## Roadmap
9
9
 
10
- - [ ] ReadPaths
11
10
  - [ ] Flesh out job runners
12
- - [x] Destination query filters
13
- - [x] Setters for metadata
14
11
  - [ ] Rename jobs and paths
12
+ - [ ] Better dependency tracking
13
+ - [ ] Better query filters
15
14
 
16
- ## Helpers
15
+ ## Project: Jobs
17
16
 
18
- - Read
17
+ Jobs was originally a generic concept, but after working it's clear that there are two main categories of jobs: async writes and data fetching. We can probably handle async writes with inbuilt logic. So, instead of a "job", we should have "read uri"? That way we can cache all the uris.
package/lib/bundle.js CHANGED
@@ -5,9 +5,10 @@ import readSources from "./readSources.js"
5
5
  import runJobs from "./runJobs.js"
6
6
  import writeDestinations from "./writeDestinations.js"
7
7
  import { default as createDatabase } from "./createDatabase.js"
8
+ import { stopwatch } from "./utils/index.js"
9
+ import { styleText } from "node:util"
8
10
 
9
11
  /** @import {Database} from "./createDatabase.js" */
10
- /** @import {ParsedPath} from "node:path" */
11
12
 
12
13
  /**
13
14
  * @typedef {object} VotivePlugin
@@ -18,17 +19,40 @@ import { default as createDatabase } from "./createDatabase.js"
18
19
  */
19
20
 
20
21
  /**
21
- * @typedef {object} VotiveProcessor
22
- * @property {ProcessorFilter} [filter]
23
- * @property {ProcessorSyntax} syntax
24
- * @property {ProcessorRead} [read]
25
- * @property {ProcessorWrite} [write]
22
+ * @typedef {object} VotiveProcessorCommon
23
+ * @property {string[]} extensions
24
+ * @property {ReadResource} [readResource]
25
+ * @property {ProcessorWrite} [writeFile]
26
+ * @property {ReadFolder} [readFolder]
27
+ * @property {ReadAbstract} [transformFile]
28
+ */
29
+
30
+ /**
31
+ * @typedef {VotiveProcessorCommon & {
32
+ * format: "buffer",
33
+ * readFile: ReadPath | undefined
34
+ * }} VotiveProcessorBuffer
35
+ */
36
+
37
+ /**
38
+ * @typedef {VotiveProcessorCommon & {
39
+ * format: "text",
40
+ * readFile: ReadText | undefined
41
+ * }} VotiveProcessorText
42
+ */
43
+
44
+ /**
45
+ * @typedef {VotiveProcessorBuffer | VotiveProcessorText} VotiveProcessor
46
+ */
47
+
48
+ /**
49
+ * @typedef {object} ReadResource
26
50
  */
27
51
 
28
52
  /**
29
53
  * Filter for files that the processor will read from.
30
54
  * @typedef {object} ProcessorFilter
31
- * @property {string[]} extensions
55
+ * @property {string} extensions
32
56
  */
33
57
 
34
58
  /**
@@ -39,7 +63,6 @@ import { default as createDatabase } from "./createDatabase.js"
39
63
  /**
40
64
  * @typedef {object} ProcessorRead
41
65
  * @property {ReadPath} [path]
42
- * @property {ReadURL} [url]
43
66
  * @property {ReadText} [text]
44
67
  * @property {ReadAbstract} [abstract]
45
68
  * @property {ReadFolder} [folder]
@@ -51,14 +74,7 @@ import { default as createDatabase } from "./createDatabase.js"
51
74
  * @param {string} filePath
52
75
  * @param {Database} database
53
76
  * @param {VotiveConfig} config
54
- * @returns {Promise<ReadTextResult>}
55
- */
56
-
57
- /**
58
- * Reads a the response from a URL and returns arbitrary data.
59
- * @callback ReadURL
60
- * @param {Response} response
61
- * @returns {object}
77
+ * @returns {Job[] | undefined}
62
78
  */
63
79
 
64
80
  /**
@@ -68,14 +84,14 @@ import { default as createDatabase } from "./createDatabase.js"
68
84
  * @param {string} destinationPath
69
85
  * @param {Database} database
70
86
  * @param {VotiveConfig} config
71
- * @returns {ReadTextResult}
87
+ * @returns {ReadTextResult | undefined}
72
88
  */
73
89
 
74
90
  /**
75
91
  * @typedef {object} ReadTextResult
76
92
  * @property {Jobs} [jobs]
77
- * @property {object} metadata
78
- * @property {Abstract} abstract
93
+ * @property {object} [metadata]
94
+ * @property {Abstract} [abstract]
79
95
  */
80
96
 
81
97
  /**
@@ -110,15 +126,14 @@ import { default as createDatabase } from "./createDatabase.js"
110
126
 
111
127
  /**
112
128
  * @callback ReadFolder
113
- * @param {object} folder
129
+ * @param {object} Folder
114
130
  * @param {Database} database
115
131
  * @param {VotiveConfig} config
116
- * @param {boolean} isRoot
117
- * @returns {{ jobs?: Jobs, destinations?: Destination[] }}
132
+ * @returns {{ jobs?: Jobs, targets?: Target[] }}
118
133
  */
119
134
 
120
135
  /**
121
- * @typedef {object} Destination
136
+ * @typedef {object} Target
122
137
  * @property {string} path
123
138
  * @property {object} metadata
124
139
  * @property {Abstract} abstract
@@ -136,7 +151,7 @@ import { default as createDatabase } from "./createDatabase.js"
136
151
  * @param {object} destination
137
152
  * @param {Database} database
138
153
  * @param {VotiveConfig} config
139
- * @returns {{ data: string, buffer: Buffer, encoding?: BufferEncoding = 'utf-8' }}
154
+ * @returns {{ data: string, encoding?: BufferEncoding = 'utf-8' }}
140
155
  */
141
156
 
142
157
  /**
@@ -151,22 +166,18 @@ import { default as createDatabase } from "./createDatabase.js"
151
166
  * Run a job.
152
167
  * @typedef {object} Job
153
168
  * @property {object} data
154
- * @property {"text" | "blob" | "json"} format
155
- * @property {string} [syntax]
169
+ * @property {string} runner
170
+ * @property {string} [plugin]
156
171
  */
157
172
 
158
173
  /**
159
- * @typedef {object} PathInfo
160
- * @property {string[]} dir
161
- * @property {ParsedPath["name"]} name
162
- * @property {ParsedPath["ext"]} ext
163
- * @property {boolean} [inRootDir]
174
+ * @typedef {(Pick<path.ParsedPath, "root" | "base" | "ext" | "name") & { dir: string[] | string }} RouteInfo
164
175
  */
165
176
 
166
177
  /**
167
178
  * @callback Router
168
- * @param {PathInfo} path
169
- * @returns {PathInfo | false | undefined}
179
+ * @param {RouteInfo} path
180
+ * @returns {Partial<RouteInfo> | path.ParsedPath | false}
170
181
  */
171
182
 
172
183
  /**
@@ -174,6 +185,7 @@ import { default as createDatabase } from "./createDatabase.js"
174
185
  * @property {string} sourceFolder
175
186
  * @property {string} destinationFolder
176
187
  * @property {VotivePlugin[]} plugins
188
+ * @property {boolean} verbose
177
189
  */
178
190
 
179
191
  /**
@@ -191,13 +203,11 @@ import { default as createDatabase } from "./createDatabase.js"
191
203
  * @param {Database | undefined} [cache]
192
204
  */
193
205
  async function bundle(config, cache) {
194
- // TODO: Ensure all cached destinations exist as expected
195
206
 
196
207
  // Map out all processors
197
208
  const processors = config.plugins
198
209
  && config.plugins.flatMap(plugin => plugin.processors && plugin.processors.map(processor => ({ plugin, processor })))
199
210
 
200
- // Create database
201
211
  const database = cache || createDatabase(path.join(config.sourceFolder, ".votive.db"))
202
212
 
203
213
  /*
@@ -211,38 +221,94 @@ async function bundle(config, cache) {
211
221
  even out.
212
222
  */
213
223
 
224
+ // database.begin()
225
+
226
+ const sourceTime = stopwatch("build", "read sources in", config.verbose)
214
227
  // Read folders and source files
215
228
  const { folders, sources } = await readSources(config, database, processors)
216
229
 
217
- // Map out jobs from source files
218
- const sourcesJobs = sources.flatMap(source => source.jobs) || []
230
+ sourceTime()
219
231
 
220
- // Process source file abstracts and map jobs
221
- const { abstractsJobs } = readAbstracts(sources, config, database, processors)
232
+ if(config.verbose) console.info(`${styleText("dim", "build:")} ${styleText("magenta", `found ${sources.length} stale files`)}`)
222
233
 
223
- // Scan folders and map out jobs
224
- const foldersJobs = readFolders(folders, config, database, processors) || []
234
+ if (sources.length) {
235
+ // Map out jobs from source files
236
+ const sourcesJobs = sources.flatMap(source => source.jobs) || []
225
237
 
226
- // Write destination files
227
- await writeDestinations(config, database)
238
+ // Process source file abstracts and map jobs
239
+ const { abstractsJobs } = readAbstracts(sources, config, database, processors)
228
240
 
229
- // Run all jobs
230
- await runJobs([
231
- ...sourcesJobs,
232
- ...abstractsJobs,
233
- ...foldersJobs
234
- ], config, database)
241
+ // Scan folders and map out jobs
242
+ const foldersJobs = readFolders(folders, config, database, processors) || []
235
243
 
244
+ const writeTime = stopwatch("build", "wrote files in", config.verbose)
245
+ // Write destination files
246
+ await writeDestinations(config, database)
236
247
 
237
- await writeDestinations(config, database)
248
+ writeTime()
238
249
 
239
- // Back up database (only if in-memory first run)
240
- await database.saveDB()
250
+ // database.commit()
241
251
 
242
- const stale = database.getStaleDestinations()
243
- if(stale.length > 0) await bundle(config, cache)
252
+ await database.saveDB(sources)
253
+ }
254
+ // Run all jobs
255
+ // await runJobs([
256
+ // ...sourcesJobs,
257
+ // ...abstractsJobs,
258
+ // ...foldersJobs
259
+ // ], config, database)
260
+
261
+ // Back up database (only if in-memory first run)
244
262
 
245
263
  return database
246
264
  }
247
265
 
248
- export default bundle
266
+ /**
267
+ * @param {VotiveConfig} config
268
+ */
269
+ async function bundler(config) {
270
+ let queue = []
271
+ let cache
272
+
273
+ async function step() {
274
+ if (queue.length === 0) {
275
+ if(config.verbose) console.info(`${styleText("dim", "build:")} ${styleText("magenta", "starting build")}`)
276
+ /*
277
+ If queue is empty, bundle.
278
+ */
279
+ if (!cache) {
280
+ queue.push(bundle(config))
281
+ cache = await queue[0]
282
+ } else {
283
+ "cache"
284
+ queue.push(bundle(config, cache))
285
+ await queue[0]
286
+ }
287
+ queue.shift()
288
+ return cache
289
+ } else if (queue.length === 1) {
290
+ /*
291
+ If currently bundling, prepare another
292
+ bundle as cleanup.
293
+ */
294
+ if(config.verbose) console.info(`${styleText("dim", "build:")} ${styleText("magenta", "queueing build")}`)
295
+
296
+ let bundling
297
+ queue.push(bundling)
298
+ bundling = await bundle(config, cache)
299
+ queue.shift()
300
+ return cache
301
+ } else {
302
+ /*
303
+ If cleanup is already queued, do nothing.
304
+ */
305
+ if(config.verbose) console.info(`${styleText("dim", "build:")} ${styleText("magenta", "already queued")}`)
306
+ await Promise.all(queue)
307
+ return cache
308
+ }
309
+ }
310
+
311
+ return step
312
+ }
313
+
314
+ export default bundler