@dfosco/storyboard-react 4.0.0-beta.3 → 4.0.0-beta.4
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/package.json +3 -3
- package/src/vite/data-plugin.js +107 -14
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dfosco/storyboard-react",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@dfosco/storyboard-core": "4.0.0-beta.
|
|
7
|
-
"@dfosco/tiny-canvas": "4.0.0-beta.
|
|
6
|
+
"@dfosco/storyboard-core": "4.0.0-beta.4",
|
|
7
|
+
"@dfosco/tiny-canvas": "4.0.0-beta.4",
|
|
8
8
|
"@neodrag/react": "^2.3.1",
|
|
9
9
|
"glob": "^11.0.0",
|
|
10
10
|
"jsonc-parser": "^3.3.1"
|
package/src/vite/data-plugin.js
CHANGED
|
@@ -155,14 +155,101 @@ function getLastModified(root, dirPath) {
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Batch-fetch git metadata (author + lastModified) for multiple files in a
|
|
160
|
+
* single subprocess, avoiding per-file git overhead during startup.
|
|
161
|
+
*
|
|
162
|
+
* Returns a Map<absPath, { gitAuthor: string|null, lastModified: string|null }>
|
|
163
|
+
*/
|
|
164
|
+
function batchGitMetadata(root, filePaths) {
|
|
165
|
+
const result = new Map()
|
|
166
|
+
if (filePaths.length === 0) return result
|
|
167
|
+
|
|
168
|
+
// Initialize all entries
|
|
169
|
+
for (const fp of filePaths) {
|
|
170
|
+
result.set(fp, { gitAuthor: null, lastModified: null })
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
// Batch lastModified: one git log call with all paths
|
|
175
|
+
// git log -1 gives the most recent commit touching any of these paths,
|
|
176
|
+
// but we need per-path data. Use --name-only to correlate.
|
|
177
|
+
// For efficiency, use a single git log with --format and --name-only
|
|
178
|
+
// that outputs one record per commit touching these files.
|
|
179
|
+
const allDirs = [...new Set(filePaths.map(fp => path.dirname(fp)))]
|
|
180
|
+
const dirsArg = allDirs.map(d => `"${d}"`).join(' ')
|
|
181
|
+
|
|
182
|
+
// Get lastModified per directory in one call using git log --format
|
|
183
|
+
// We output "MARKER<sep>dir<sep>date" per commit, then take the latest per dir.
|
|
184
|
+
const logResult = execSync(
|
|
185
|
+
`git log --format="%aI" --name-only -- ${dirsArg}`,
|
|
186
|
+
{ cwd: root, encoding: 'utf-8', timeout: 10000, maxBuffer: 1024 * 1024 },
|
|
187
|
+
).trim()
|
|
188
|
+
|
|
189
|
+
if (logResult) {
|
|
190
|
+
// Parse: alternating date lines and filename lines separated by blank lines
|
|
191
|
+
const blocks = logResult.split('\n\n')
|
|
192
|
+
const dirDates = new Map() // dir → most recent date
|
|
193
|
+
for (const block of blocks) {
|
|
194
|
+
const lines = block.split('\n').filter(Boolean)
|
|
195
|
+
if (lines.length < 2) continue
|
|
196
|
+
const date = lines[0]
|
|
197
|
+
for (let li = 1; li < lines.length; li++) {
|
|
198
|
+
const fileLine = lines[li].trim()
|
|
199
|
+
if (!fileLine) continue
|
|
200
|
+
const dir = path.dirname(path.resolve(root, fileLine))
|
|
201
|
+
if (!dirDates.has(dir)) {
|
|
202
|
+
dirDates.set(dir, date)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
for (const fp of filePaths) {
|
|
207
|
+
const dir = path.dirname(fp)
|
|
208
|
+
const entry = result.get(fp)
|
|
209
|
+
if (dirDates.has(dir) && entry) {
|
|
210
|
+
entry.lastModified = dirDates.get(dir)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
} catch { /* git not available or failed — leave nulls */ }
|
|
215
|
+
|
|
216
|
+
// Batch gitAuthor: use git log for each file's creation author.
|
|
217
|
+
// Unfortunately --follow --diff-filter=A doesn't combine well with multiple
|
|
218
|
+
// paths, so batch them in a single shell invocation using a for loop.
|
|
219
|
+
try {
|
|
220
|
+
const relPaths = filePaths.map(fp => path.relative(root, fp))
|
|
221
|
+
// Build a shell script that outputs "PATH<tab>AUTHOR" per file
|
|
222
|
+
const cmds = relPaths.map(rp =>
|
|
223
|
+
`echo -n "${rp}\\t"; git log --follow --diff-filter=A --format="%aN" -- "${rp}" | tail -1`
|
|
224
|
+
).join('; ')
|
|
225
|
+
const authorResult = execSync(cmds, {
|
|
226
|
+
cwd: root, encoding: 'utf-8', timeout: 10000, shell: true, maxBuffer: 1024 * 1024,
|
|
227
|
+
}).trim()
|
|
228
|
+
|
|
229
|
+
if (authorResult) {
|
|
230
|
+
for (const line of authorResult.split('\n')) {
|
|
231
|
+
const tabIdx = line.indexOf('\t')
|
|
232
|
+
if (tabIdx < 0) continue
|
|
233
|
+
const relPath = line.slice(0, tabIdx)
|
|
234
|
+
const author = line.slice(tabIdx + 1).trim()
|
|
235
|
+
if (!author) continue
|
|
236
|
+
const absPath2 = path.resolve(root, relPath)
|
|
237
|
+
const entry = result.get(absPath2)
|
|
238
|
+
if (entry) entry.gitAuthor = author
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
} catch { /* git not available */ }
|
|
242
|
+
|
|
243
|
+
return result
|
|
244
|
+
}
|
|
245
|
+
|
|
158
246
|
/**
|
|
159
247
|
* Scan the repo for all data files, validate uniqueness, return the index.
|
|
160
248
|
*/
|
|
161
249
|
function buildIndex(root) {
|
|
162
|
-
const ignore = ['node_modules/**', 'dist/**', '.git/**']
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
const canvasFiles = globSync(`src/${CANVAS_GLOB_PATTERN}`, { cwd: root, ignore, absolute: false })
|
|
250
|
+
const ignore = ['node_modules/**', 'dist/**', '.git/**', '.worktrees/**', 'public/**']
|
|
251
|
+
const files = globSync(GLOB_PATTERN, { cwd: root, ignore, absolute: false })
|
|
252
|
+
const canvasFiles = globSync(CANVAS_GLOB_PATTERN, { cwd: root, ignore, absolute: false })
|
|
166
253
|
|
|
167
254
|
// Detect nested .folder/ directories (not supported)
|
|
168
255
|
// Scan directories directly since empty nested folders have no data files
|
|
@@ -340,6 +427,13 @@ function generateModule({ index, protoFolders, flowRoutes, canvasRoutes }, root)
|
|
|
340
427
|
const resolvedFlowRoutes = {} // flow name → resolved route (for multi-flow logging)
|
|
341
428
|
let i = 0
|
|
342
429
|
|
|
430
|
+
// Batch-fetch git metadata for all prototype + canvas files in 1-2 subprocesses
|
|
431
|
+
const gitPaths = [
|
|
432
|
+
...Object.values(index.prototype || {}),
|
|
433
|
+
...Object.values(index.canvas || {}),
|
|
434
|
+
]
|
|
435
|
+
const gitMeta = batchGitMetadata(root, gitPaths)
|
|
436
|
+
|
|
343
437
|
for (const suffix of INDEX_KEYS) {
|
|
344
438
|
for (const [name, absPath] of Object.entries(index[suffix])) {
|
|
345
439
|
const varName = `_d${i++}`
|
|
@@ -350,18 +444,17 @@ function generateModule({ index, protoFolders, flowRoutes, canvasRoutes }, root)
|
|
|
350
444
|
|
|
351
445
|
// Auto-fill gitAuthor for prototype metadata from git history
|
|
352
446
|
if (suffix === 'prototype' && parsed && !parsed.gitAuthor) {
|
|
353
|
-
const
|
|
354
|
-
if (gitAuthor) {
|
|
355
|
-
parsed = { ...parsed, gitAuthor }
|
|
447
|
+
const meta = gitMeta.get(absPath)
|
|
448
|
+
if (meta?.gitAuthor) {
|
|
449
|
+
parsed = { ...parsed, gitAuthor: meta.gitAuthor }
|
|
356
450
|
}
|
|
357
451
|
}
|
|
358
452
|
|
|
359
453
|
// Auto-fill lastModified from git history for prototypes
|
|
360
454
|
if (suffix === 'prototype' && parsed) {
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
parsed = { ...parsed, lastModified }
|
|
455
|
+
const meta = gitMeta.get(absPath)
|
|
456
|
+
if (meta?.lastModified) {
|
|
457
|
+
parsed = { ...parsed, lastModified: meta.lastModified }
|
|
365
458
|
}
|
|
366
459
|
}
|
|
367
460
|
|
|
@@ -400,9 +493,9 @@ function generateModule({ index, protoFolders, flowRoutes, canvasRoutes }, root)
|
|
|
400
493
|
|
|
401
494
|
// Auto-fill gitAuthor for canvas metadata from git history
|
|
402
495
|
if (suffix === 'canvas' && parsed && !parsed.gitAuthor) {
|
|
403
|
-
const
|
|
404
|
-
if (gitAuthor) {
|
|
405
|
-
parsed = { ...parsed, gitAuthor }
|
|
496
|
+
const meta = gitMeta.get(absPath)
|
|
497
|
+
if (meta?.gitAuthor) {
|
|
498
|
+
parsed = { ...parsed, gitAuthor: meta.gitAuthor }
|
|
406
499
|
}
|
|
407
500
|
}
|
|
408
501
|
|