@jkwd/inbase 0.1.9 → 0.1.11

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.
@@ -0,0 +1,121 @@
1
+ import { spawnSync } from 'node:child_process'
2
+ import fs from 'node:fs'
3
+ import path from 'node:path'
4
+ import { listSourceFiles } from './scan-target.mjs'
5
+
6
+ function splitLines(text) {
7
+ if (text === '') return []
8
+ const lines = text.split('\n')
9
+ if (text.endsWith('\n')) lines.pop()
10
+ return lines
11
+ }
12
+
13
+ export function snapshotSourceTree(fromRoot, toRoot) {
14
+ if (fs.existsSync(toRoot)) fs.rmSync(toRoot, { recursive: true, force: true })
15
+ fs.mkdirSync(toRoot, { recursive: true })
16
+ for (const fileId of listSourceFiles(fromRoot)) {
17
+ const from = path.join(fromRoot, fileId)
18
+ const to = path.join(toRoot, fileId)
19
+ fs.mkdirSync(path.dirname(to), { recursive: true })
20
+ fs.copyFileSync(from, to)
21
+ }
22
+ return toRoot
23
+ }
24
+
25
+ function fileAsAddPatch(fileId, contents) {
26
+ const lines = splitLines(contents)
27
+ const count = lines.length
28
+ const hunk =
29
+ count === 0
30
+ ? []
31
+ : [`@@ -0,0 +1,${count} @@`, ...lines.map((line) => `+${line}`)]
32
+ return [
33
+ `diff --git a/${fileId} b/${fileId}`,
34
+ 'new file mode 100644',
35
+ '--- /dev/null',
36
+ `+++ b/${fileId}`,
37
+ ...hunk,
38
+ '',
39
+ ].join('\n')
40
+ }
41
+
42
+ function fileAsDeletePatch(fileId, contents) {
43
+ const lines = splitLines(contents)
44
+ const count = lines.length
45
+ const hunk =
46
+ count === 0
47
+ ? []
48
+ : [`@@ -1,${count} +0,0 @@`, ...lines.map((line) => `-${line}`)]
49
+ return [
50
+ `diff --git a/${fileId} b/${fileId}`,
51
+ 'deleted file mode 100644',
52
+ `--- a/${fileId}`,
53
+ '+++ /dev/null',
54
+ ...hunk,
55
+ '',
56
+ ].join('\n')
57
+ }
58
+
59
+ function rewriteGitPaths(patch, fileId) {
60
+ return patch
61
+ .split('\n')
62
+ .map((line) => {
63
+ if (line.startsWith('diff --git ')) {
64
+ return `diff --git a/${fileId} b/${fileId}`
65
+ }
66
+ if (line.startsWith('--- ')) {
67
+ return line.includes('/dev/null') ? '--- /dev/null' : `--- a/${fileId}`
68
+ }
69
+ if (line.startsWith('+++ ')) {
70
+ return line.includes('/dev/null') ? '+++ /dev/null' : `+++ b/${fileId}`
71
+ }
72
+ return line
73
+ })
74
+ .join('\n')
75
+ }
76
+
77
+ function gitFileDiff(beforePath, afterPath, fileId) {
78
+ const result = spawnSync(
79
+ 'git',
80
+ ['diff', '--no-index', '--no-color', '--no-ext-diff', '--', beforePath, afterPath],
81
+ {
82
+ encoding: 'utf8',
83
+ maxBuffer: 32 * 1024 * 1024,
84
+ },
85
+ )
86
+ if (result.status !== 0 && result.status !== 1) {
87
+ throw new Error(result.stderr?.trim() || `git diff failed for ${fileId}`)
88
+ }
89
+ const stdout = result.stdout?.trimEnd()
90
+ if (!stdout) return ''
91
+ return `${rewriteGitPaths(stdout, fileId).trimEnd()}\n`
92
+ }
93
+
94
+ export function diffSourceTrees(beforeRoot, afterRoot) {
95
+ const before = new Set(listSourceFiles(beforeRoot))
96
+ const after = new Set(listSourceFiles(afterRoot))
97
+ const ids = [...new Set([...before, ...after])].sort((left, right) =>
98
+ left.localeCompare(right),
99
+ )
100
+ const parts = []
101
+ for (const fileId of ids) {
102
+ const beforePath = path.join(beforeRoot, fileId)
103
+ const afterPath = path.join(afterRoot, fileId)
104
+ const had = before.has(fileId)
105
+ const has = after.has(fileId)
106
+ if (!had && has) {
107
+ parts.push(fileAsAddPatch(fileId, fs.readFileSync(afterPath, 'utf8')))
108
+ continue
109
+ }
110
+ if (had && !has) {
111
+ parts.push(fileAsDeletePatch(fileId, fs.readFileSync(beforePath, 'utf8')))
112
+ continue
113
+ }
114
+ const beforeText = fs.readFileSync(beforePath, 'utf8')
115
+ const afterText = fs.readFileSync(afterPath, 'utf8')
116
+ if (beforeText === afterText) continue
117
+ const patch = gitFileDiff(beforePath, afterPath, fileId)
118
+ if (patch) parts.push(patch)
119
+ }
120
+ return parts.join('\n')
121
+ }