@epic-web/workshop-utils 0.0.0-semantically-released
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 +3 -0
- package/dist/esm/apps.server.d.ts +4205 -0
- package/dist/esm/apps.server.d.ts.map +1 -0
- package/dist/esm/apps.server.js +1198 -0
- package/dist/esm/apps.server.js.map +1 -0
- package/dist/esm/cache.server.d.ts +940 -0
- package/dist/esm/cache.server.d.ts.map +1 -0
- package/dist/esm/cache.server.js +161 -0
- package/dist/esm/cache.server.js.map +1 -0
- package/dist/esm/compile-mdx.server.d.ts +12 -0
- package/dist/esm/compile-mdx.server.d.ts.map +1 -0
- package/dist/esm/compile-mdx.server.js +285 -0
- package/dist/esm/compile-mdx.server.js.map +1 -0
- package/dist/esm/config.server.d.ts +348 -0
- package/dist/esm/config.server.d.ts.map +1 -0
- package/dist/esm/config.server.js +231 -0
- package/dist/esm/config.server.js.map +1 -0
- package/dist/esm/db.server.d.ts +463 -0
- package/dist/esm/db.server.d.ts.map +1 -0
- package/dist/esm/db.server.js +260 -0
- package/dist/esm/db.server.js.map +1 -0
- package/dist/esm/diff.server.d.ts +18 -0
- package/dist/esm/diff.server.d.ts.map +1 -0
- package/dist/esm/diff.server.js +437 -0
- package/dist/esm/diff.server.js.map +1 -0
- package/dist/esm/env.server.d.ts +61 -0
- package/dist/esm/env.server.d.ts.map +1 -0
- package/dist/esm/env.server.js +42 -0
- package/dist/esm/env.server.js.map +1 -0
- package/dist/esm/epic-api.server.d.ts +227 -0
- package/dist/esm/epic-api.server.d.ts.map +1 -0
- package/dist/esm/epic-api.server.js +529 -0
- package/dist/esm/epic-api.server.js.map +1 -0
- package/dist/esm/git.server.d.ts +49 -0
- package/dist/esm/git.server.d.ts.map +1 -0
- package/dist/esm/git.server.js +135 -0
- package/dist/esm/git.server.js.map +1 -0
- package/dist/esm/iframe-sync.d.ts +10 -0
- package/dist/esm/iframe-sync.d.ts.map +1 -0
- package/dist/esm/iframe-sync.js +97 -0
- package/dist/esm/iframe-sync.js.map +1 -0
- package/dist/esm/modified-time.server.d.ts +7 -0
- package/dist/esm/modified-time.server.d.ts.map +1 -0
- package/dist/esm/modified-time.server.js +80 -0
- package/dist/esm/modified-time.server.js.map +1 -0
- package/dist/esm/notifications.server.d.ts +56 -0
- package/dist/esm/notifications.server.d.ts.map +1 -0
- package/dist/esm/notifications.server.js +65 -0
- package/dist/esm/notifications.server.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/playwright.server.d.ts +6 -0
- package/dist/esm/playwright.server.d.ts.map +1 -0
- package/dist/esm/playwright.server.js +95 -0
- package/dist/esm/playwright.server.js.map +1 -0
- package/dist/esm/process-manager.server.d.ts +77 -0
- package/dist/esm/process-manager.server.d.ts.map +1 -0
- package/dist/esm/process-manager.server.js +266 -0
- package/dist/esm/process-manager.server.js.map +1 -0
- package/dist/esm/test.d.ts +16 -0
- package/dist/esm/test.d.ts.map +1 -0
- package/dist/esm/test.js +56 -0
- package/dist/esm/test.js.map +1 -0
- package/dist/esm/timing.server.d.ts +20 -0
- package/dist/esm/timing.server.d.ts.map +1 -0
- package/dist/esm/timing.server.js +88 -0
- package/dist/esm/timing.server.js.map +1 -0
- package/dist/esm/user.server.d.ts +17 -0
- package/dist/esm/user.server.d.ts.map +1 -0
- package/dist/esm/user.server.js +38 -0
- package/dist/esm/user.server.js.map +1 -0
- package/dist/esm/utils.d.ts +2 -0
- package/dist/esm/utils.d.ts.map +1 -0
- package/dist/esm/utils.js +13 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/esm/utils.server.d.ts +9 -0
- package/dist/esm/utils.server.d.ts.map +1 -0
- package/dist/esm/utils.server.js +45 -0
- package/dist/esm/utils.server.js.map +1 -0
- package/package.json +221 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import os from 'os';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { execa } from 'execa';
|
|
4
|
+
import fsExtra from 'fs-extra';
|
|
5
|
+
import ignore from 'ignore';
|
|
6
|
+
import parseGitDiff from 'parse-git-diff';
|
|
7
|
+
import { bundledLanguagesInfo } from 'shiki/langs';
|
|
8
|
+
import { getForceFreshForDir, getRelativePath, getWorkshopRoot, modifiedTimes, } from './apps.server.js';
|
|
9
|
+
import { cachified, diffCodeCache, diffFilesCache } from './cache.server.js';
|
|
10
|
+
import { compileMarkdownString } from './compile-mdx.server.js';
|
|
11
|
+
import { modifiedMoreRecentlyThan } from './modified-time.server.js';
|
|
12
|
+
const epicshopTempDir = path.join(os.tmpdir(), 'epicshop');
|
|
13
|
+
const isDeployed = ENV.EPICSHOP_DEPLOYED;
|
|
14
|
+
const diffTmpDir = path.join(epicshopTempDir, 'diff');
|
|
15
|
+
function diffPathToRelative(filePath) {
|
|
16
|
+
let normalizedPath = path.normalize(filePath.replace(/^("|')|("|')$/g, ''));
|
|
17
|
+
if (normalizedPath.startsWith('a\\') ||
|
|
18
|
+
normalizedPath.startsWith('b\\') ||
|
|
19
|
+
normalizedPath.startsWith('a/') ||
|
|
20
|
+
normalizedPath.startsWith('b/')) {
|
|
21
|
+
normalizedPath = normalizedPath.slice(2);
|
|
22
|
+
}
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
24
|
+
const [workshopRootDirname, appId, id, ...relativePath] = normalizedPath
|
|
25
|
+
.replace(process.platform === 'win32' || normalizedPath.startsWith(path.sep)
|
|
26
|
+
? `${diffTmpDir}${path.sep}`
|
|
27
|
+
: `${diffTmpDir.slice(1)}${path.sep}`, '')
|
|
28
|
+
.split(path.sep);
|
|
29
|
+
return relativePath.join(path.sep);
|
|
30
|
+
}
|
|
31
|
+
function getLanguage(ext) {
|
|
32
|
+
return (bundledLanguagesInfo.find((l) => l.id === ext || l.aliases?.includes(ext))
|
|
33
|
+
?.id ?? 'text');
|
|
34
|
+
}
|
|
35
|
+
function getFileCodeblocks(file, filePathApp1, filePathApp2, type) {
|
|
36
|
+
if (!file.chunks.length) {
|
|
37
|
+
return [
|
|
38
|
+
`<p className="m-0 p-4 border-b text-muted-foreground">No changes</p>`,
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
const filepath = diffPathToRelative(file.type === 'RenamedFile' ? file.pathAfter : file.path);
|
|
42
|
+
const extension = path.extname(filepath).slice(1);
|
|
43
|
+
const lang = getLanguage(extension);
|
|
44
|
+
const pathToCopy = file.type === 'RenamedFile' ? file.pathBefore : file.path;
|
|
45
|
+
const relativePath = diffPathToRelative(pathToCopy);
|
|
46
|
+
const markdownLines = [];
|
|
47
|
+
for (const chunk of file.chunks) {
|
|
48
|
+
const removedLineNumbers = [];
|
|
49
|
+
const addedLineNumbers = [];
|
|
50
|
+
const lines = [];
|
|
51
|
+
let toStartLine = 0;
|
|
52
|
+
let startLine = 1;
|
|
53
|
+
if (chunk.type === 'BinaryFilesChunk') {
|
|
54
|
+
lines.push(type === 'AddedFile'
|
|
55
|
+
? `Binary file added`
|
|
56
|
+
: type === 'DeletedFile'
|
|
57
|
+
? 'Binary file deleted'
|
|
58
|
+
: 'Binary file changed');
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
startLine =
|
|
62
|
+
chunk.type === 'Chunk'
|
|
63
|
+
? chunk.fromFileRange.start
|
|
64
|
+
: chunk.type === 'CombinedChunk'
|
|
65
|
+
? chunk.fromFileRangeA.start
|
|
66
|
+
: 1;
|
|
67
|
+
toStartLine = chunk.toFileRange.start;
|
|
68
|
+
for (let lineNumber = 0; lineNumber < chunk.changes.length; lineNumber++) {
|
|
69
|
+
const change = chunk.changes[lineNumber];
|
|
70
|
+
if (!change)
|
|
71
|
+
continue;
|
|
72
|
+
lines.push(change.content);
|
|
73
|
+
switch (change.type) {
|
|
74
|
+
case 'AddedLine': {
|
|
75
|
+
addedLineNumbers.push(startLine + lineNumber);
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case 'DeletedLine': {
|
|
79
|
+
removedLineNumbers.push(startLine + lineNumber);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
default: {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const params = [
|
|
89
|
+
['filename', relativePath.replace(/\\/g, '\\\\')],
|
|
90
|
+
['start', startLine.toString()],
|
|
91
|
+
removedLineNumbers.length
|
|
92
|
+
? ['remove', removedLineNumbers.join(',')]
|
|
93
|
+
: null,
|
|
94
|
+
addedLineNumbers.length ? ['add', addedLineNumbers.join(',')] : null,
|
|
95
|
+
]
|
|
96
|
+
.filter(Boolean)
|
|
97
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
98
|
+
.join(' ');
|
|
99
|
+
const launchEditorClassName = 'border hover:bg-foreground/20 rounded px-2 py-0.5 font-mono text-xs font-semibold';
|
|
100
|
+
function launchEditor(appNum, line) {
|
|
101
|
+
if (isDeployed) {
|
|
102
|
+
if (type === 'DeletedFile' && appNum === 2)
|
|
103
|
+
return '';
|
|
104
|
+
if (type === 'AddedFile' && appNum === 1)
|
|
105
|
+
return '';
|
|
106
|
+
}
|
|
107
|
+
const label = (type === 'AddedFile' && appNum === 1) ||
|
|
108
|
+
(type === 'DeletedFile' && appNum === 2)
|
|
109
|
+
? `CREATE in APP ${appNum}`
|
|
110
|
+
: `OPEN in APP ${appNum}`;
|
|
111
|
+
const file = JSON.stringify(appNum === 1 ? filePathApp1 : filePathApp2);
|
|
112
|
+
const fixedTitle = getRelativePath(file);
|
|
113
|
+
return `
|
|
114
|
+
<LaunchEditor file=${file} line={${line}}>
|
|
115
|
+
<span title="${fixedTitle}" className="${launchEditorClassName}">${label}</span>
|
|
116
|
+
</LaunchEditor>`;
|
|
117
|
+
}
|
|
118
|
+
markdownLines.push(`
|
|
119
|
+
<div className="relative">
|
|
120
|
+
|
|
121
|
+
\`\`\`${lang} ${params}
|
|
122
|
+
${lines.join('\n')}
|
|
123
|
+
\`\`\`
|
|
124
|
+
|
|
125
|
+
<div className="flex gap-4 absolute top-1 right-3 items-center">
|
|
126
|
+
${launchEditor(1, startLine)}
|
|
127
|
+
<div className="display-alt-down flex gap-2">
|
|
128
|
+
<LaunchEditor file=${JSON.stringify(filePathApp1)} syncTo={{file: ${JSON.stringify(filePathApp2)}}}>
|
|
129
|
+
<span className="block ${launchEditorClassName}">
|
|
130
|
+
<Icon name="ArrowLeft" title="Copy app 2 file to app 1" />
|
|
131
|
+
</span>
|
|
132
|
+
</LaunchEditor>
|
|
133
|
+
<LaunchEditor file=${JSON.stringify(filePathApp2)} syncTo={{file: ${JSON.stringify(filePathApp1)}}}>
|
|
134
|
+
<span className="block ${launchEditorClassName}">
|
|
135
|
+
<Icon name="ArrowRight" title="Copy app 1 file to app 2" />
|
|
136
|
+
</span>
|
|
137
|
+
</LaunchEditor>
|
|
138
|
+
</div>
|
|
139
|
+
${launchEditor(2, toStartLine)}
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
</div>
|
|
143
|
+
`);
|
|
144
|
+
}
|
|
145
|
+
return markdownLines;
|
|
146
|
+
}
|
|
147
|
+
const DEFAULT_IGNORE_PATTERNS = [
|
|
148
|
+
'**/README.*',
|
|
149
|
+
'**/package-lock.json',
|
|
150
|
+
'**/.DS_Store',
|
|
151
|
+
'**/.vscode',
|
|
152
|
+
'**/.idea',
|
|
153
|
+
'**/.git',
|
|
154
|
+
'**/*.db',
|
|
155
|
+
'**/epicshop/**',
|
|
156
|
+
];
|
|
157
|
+
async function copyUnignoredFiles(srcDir, destDir, ignoreList) {
|
|
158
|
+
const key = `COPY_${srcDir}__${destDir}__${ignoreList.join('_')}`;
|
|
159
|
+
await cachified({
|
|
160
|
+
key,
|
|
161
|
+
cache: diffCodeCache,
|
|
162
|
+
forceFresh: getForceFreshForDir(diffCodeCache.get(key), srcDir),
|
|
163
|
+
async getFreshValue() {
|
|
164
|
+
// @ts-ignore 🤷♂️ weird module stuff
|
|
165
|
+
const ig = ignore().add(ignoreList);
|
|
166
|
+
await fsExtra.remove(destDir);
|
|
167
|
+
await fsExtra.copy(srcDir, destDir, {
|
|
168
|
+
filter: async (file) => {
|
|
169
|
+
if (file === srcDir)
|
|
170
|
+
return true;
|
|
171
|
+
return !ig.ignores(path.relative(srcDir, file));
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
async function prepareForDiff(app1, app2) {
|
|
178
|
+
const id = Math.random().toString(36).slice(2);
|
|
179
|
+
const app1CopyPath = path.join(diffTmpDir, path.basename(getWorkshopRoot()), app1.name, id);
|
|
180
|
+
const app2CopyPath = path.join(diffTmpDir, path.basename(getWorkshopRoot()), app2.name, id);
|
|
181
|
+
// if everything except the `name` property of the `package.json` is the same
|
|
182
|
+
// the don't bother copying it
|
|
183
|
+
const comparePkgJson = (pkg1, pkg2) => {
|
|
184
|
+
const { name, ...rest1 } = pkg1;
|
|
185
|
+
const { name: name2, ...rest2 } = pkg2;
|
|
186
|
+
return JSON.stringify(rest1) === JSON.stringify(rest2);
|
|
187
|
+
};
|
|
188
|
+
const app1PkgJson = app1.dev.type === 'script'
|
|
189
|
+
? await fsExtra
|
|
190
|
+
.readJSON(path.join(app1.fullPath, 'package.json'))
|
|
191
|
+
.catch(() => ({}))
|
|
192
|
+
: {};
|
|
193
|
+
const app2PkgJson = app1.dev.type === 'script'
|
|
194
|
+
? await fsExtra
|
|
195
|
+
.readJSON(path.join(app2.fullPath, 'package.json'))
|
|
196
|
+
.catch(() => ({}))
|
|
197
|
+
: {};
|
|
198
|
+
const pkgJsonIgnore = comparePkgJson(app1PkgJson, app2PkgJson)
|
|
199
|
+
? ['package.json']
|
|
200
|
+
: [];
|
|
201
|
+
const workshopIgnore = [
|
|
202
|
+
...(await getDiffIgnore(path.join(getWorkshopRoot(), '.gitignore'))),
|
|
203
|
+
...(await getDiffIgnore(path.join(getWorkshopRoot(), 'epicshop', '.diffignore'))),
|
|
204
|
+
];
|
|
205
|
+
await Promise.all([
|
|
206
|
+
copyUnignoredFiles(app1.fullPath, app1CopyPath, [
|
|
207
|
+
...DEFAULT_IGNORE_PATTERNS,
|
|
208
|
+
...pkgJsonIgnore,
|
|
209
|
+
...workshopIgnore,
|
|
210
|
+
...(await getDiffIgnore(path.join(app1.fullPath, '.gitignore'))),
|
|
211
|
+
...(await getDiffIgnore(path.join(app1.fullPath, 'epicshop', '.diffignore'))),
|
|
212
|
+
]),
|
|
213
|
+
copyUnignoredFiles(app2.fullPath, app2CopyPath, [
|
|
214
|
+
...DEFAULT_IGNORE_PATTERNS,
|
|
215
|
+
...pkgJsonIgnore,
|
|
216
|
+
...workshopIgnore,
|
|
217
|
+
...(await getDiffIgnore(path.join(app2.fullPath, '.gitignore'))),
|
|
218
|
+
...(await getDiffIgnore(path.join(app2.fullPath, 'epicshop', '.diffignore'))),
|
|
219
|
+
]),
|
|
220
|
+
]);
|
|
221
|
+
return { app1CopyPath, app2CopyPath };
|
|
222
|
+
}
|
|
223
|
+
async function getDiffIgnore(filePath) {
|
|
224
|
+
return (await fsExtra.pathExists(filePath))
|
|
225
|
+
? fsExtra.readFile(filePath, 'utf8').then((content) => content
|
|
226
|
+
.split('\n')
|
|
227
|
+
.map((line) => line.trim())
|
|
228
|
+
.filter((line) => !line.startsWith('#'))
|
|
229
|
+
.filter(Boolean))
|
|
230
|
+
: [];
|
|
231
|
+
}
|
|
232
|
+
async function getForceFreshForDiff(app1, app2, cacheEntry) {
|
|
233
|
+
// don't know when the cache was created? force refresh
|
|
234
|
+
const cacheModified = cacheEntry?.metadata.createdTime;
|
|
235
|
+
if (!cacheModified)
|
|
236
|
+
return true;
|
|
237
|
+
// app1 modified after cache? force refresh
|
|
238
|
+
const app1Modified = modifiedTimes.get(app1.fullPath) ?? 0;
|
|
239
|
+
if (app1Modified > cacheModified)
|
|
240
|
+
return true;
|
|
241
|
+
// app2 modified after cache? force refresh
|
|
242
|
+
const app2Modified = modifiedTimes.get(app2.fullPath) ?? 0;
|
|
243
|
+
if (app2Modified > cacheModified)
|
|
244
|
+
return true;
|
|
245
|
+
// ok, now let's actually check the modified times of all files in the
|
|
246
|
+
// directories and as soon as we find a file that was modified more recently
|
|
247
|
+
// then we know we need to force refresh
|
|
248
|
+
const modifiedMoreRecently = await modifiedMoreRecentlyThan(cacheModified, app1.fullPath, app2.fullPath);
|
|
249
|
+
if (modifiedMoreRecently)
|
|
250
|
+
return true;
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
export async function getDiffFiles(app1, app2, { forceFresh, timings, request, } = {}) {
|
|
254
|
+
const key = `${app1.relativePath}__vs__${app2.relativePath}`;
|
|
255
|
+
const cacheEntry = diffFilesCache.get(key);
|
|
256
|
+
const result = await cachified({
|
|
257
|
+
key,
|
|
258
|
+
cache: diffFilesCache,
|
|
259
|
+
forceFresh: forceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),
|
|
260
|
+
timings,
|
|
261
|
+
request,
|
|
262
|
+
getFreshValue: () => getDiffFilesImpl(app1, app2),
|
|
263
|
+
});
|
|
264
|
+
return result;
|
|
265
|
+
}
|
|
266
|
+
function getAppTestFiles(app) {
|
|
267
|
+
return app.test.type === 'browser' ? app.test.testFiles : [];
|
|
268
|
+
}
|
|
269
|
+
async function getDiffFilesImpl(app1, app2) {
|
|
270
|
+
if (app1.name === app2.name) {
|
|
271
|
+
return [];
|
|
272
|
+
}
|
|
273
|
+
const { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2);
|
|
274
|
+
const { stdout: diffOutput } = await execa('git', [
|
|
275
|
+
'diff',
|
|
276
|
+
'--no-index',
|
|
277
|
+
'--ignore-blank-lines',
|
|
278
|
+
'--ignore-space-change',
|
|
279
|
+
app1CopyPath,
|
|
280
|
+
app2CopyPath,
|
|
281
|
+
], { cwd: diffTmpDir }).catch((e) => e);
|
|
282
|
+
void fsExtra.remove(app1CopyPath);
|
|
283
|
+
void fsExtra.remove(app2CopyPath);
|
|
284
|
+
const typesMap = {
|
|
285
|
+
ChangedFile: 'modified',
|
|
286
|
+
AddedFile: 'added',
|
|
287
|
+
DeletedFile: 'deleted',
|
|
288
|
+
RenamedFile: 'renamed',
|
|
289
|
+
};
|
|
290
|
+
const parsed = parseGitDiff(diffOutput, { noPrefix: true });
|
|
291
|
+
const testFiles = Array.from(new Set([...getAppTestFiles(app1), ...getAppTestFiles(app2)]));
|
|
292
|
+
const startLine = (file) => {
|
|
293
|
+
const chunk = file.type === 'ChangedFile' && file.chunks[0];
|
|
294
|
+
if (chunk) {
|
|
295
|
+
return chunk.type === 'Chunk'
|
|
296
|
+
? chunk.fromFileRange.start
|
|
297
|
+
: chunk.type === 'CombinedChunk'
|
|
298
|
+
? chunk.fromFileRangeA.start
|
|
299
|
+
: 1;
|
|
300
|
+
}
|
|
301
|
+
return 1;
|
|
302
|
+
};
|
|
303
|
+
return parsed.files
|
|
304
|
+
.map((file) => ({
|
|
305
|
+
// prettier-ignore
|
|
306
|
+
status: (typesMap[file.type] ?? 'unknown'),
|
|
307
|
+
path: diffPathToRelative(file.type === 'RenamedFile' ? file.pathBefore : file.path),
|
|
308
|
+
line: startLine(file),
|
|
309
|
+
}))
|
|
310
|
+
.filter((file) => !testFiles.includes(file.path));
|
|
311
|
+
}
|
|
312
|
+
export async function getDiffCode(app1, app2, { forceFresh, timings, request, } = {}) {
|
|
313
|
+
const key = `${app1.relativePath}__vs__${app2.relativePath}`;
|
|
314
|
+
const cacheEntry = diffCodeCache.get(key);
|
|
315
|
+
const result = await cachified({
|
|
316
|
+
key,
|
|
317
|
+
cache: diffCodeCache,
|
|
318
|
+
forceFresh: forceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),
|
|
319
|
+
timings,
|
|
320
|
+
request,
|
|
321
|
+
getFreshValue: () => getDiffCodeImpl(app1, app2),
|
|
322
|
+
});
|
|
323
|
+
return result;
|
|
324
|
+
}
|
|
325
|
+
async function getDiffCodeImpl(app1, app2) {
|
|
326
|
+
const markdownLines = [''];
|
|
327
|
+
if (app1.name === app2.name) {
|
|
328
|
+
markdownLines.push('<p className="p-4 text-center">You are comparing the same app</p>');
|
|
329
|
+
const code = await compileMarkdownString(markdownLines.join('\n'));
|
|
330
|
+
return code;
|
|
331
|
+
}
|
|
332
|
+
const { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2);
|
|
333
|
+
const { stdout: diffOutput } = await execa('git', [
|
|
334
|
+
'diff',
|
|
335
|
+
'--no-index',
|
|
336
|
+
app1CopyPath,
|
|
337
|
+
app2CopyPath,
|
|
338
|
+
'--color=never',
|
|
339
|
+
'--color-moved-ws=allow-indentation-change',
|
|
340
|
+
'--no-prefix',
|
|
341
|
+
'--ignore-blank-lines',
|
|
342
|
+
'--ignore-space-change',
|
|
343
|
+
], { cwd: diffTmpDir }).catch((e) => e);
|
|
344
|
+
void fsExtra.remove(app1CopyPath);
|
|
345
|
+
void fsExtra.remove(app2CopyPath);
|
|
346
|
+
const parsed = parseGitDiff(diffOutput);
|
|
347
|
+
if (!parsed.files.length) {
|
|
348
|
+
markdownLines.push('<div className="m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background">No changes</div>');
|
|
349
|
+
}
|
|
350
|
+
const app1TestFiles = getAppTestFiles(app1);
|
|
351
|
+
const app2TestFiles = getAppTestFiles(app2);
|
|
352
|
+
for (const file of parsed.files) {
|
|
353
|
+
const pathToCopy = file.type === 'RenamedFile' ? file.pathBefore : file.path;
|
|
354
|
+
const relativePath = diffPathToRelative(pathToCopy);
|
|
355
|
+
if (app1TestFiles.includes(relativePath))
|
|
356
|
+
continue;
|
|
357
|
+
const filePathApp1 = path.join(app1.fullPath, relativePath);
|
|
358
|
+
const pathToApp2 = file.type === 'RenamedFile' ? file.pathAfter : file.path;
|
|
359
|
+
const relativePathApp2 = diffPathToRelative(pathToApp2);
|
|
360
|
+
if (app2TestFiles.includes(relativePathApp2))
|
|
361
|
+
continue;
|
|
362
|
+
const filePathApp2 = path.join(app2.fullPath, relativePathApp2);
|
|
363
|
+
switch (file.type) {
|
|
364
|
+
case 'ChangedFile': {
|
|
365
|
+
markdownLines.push(`
|
|
366
|
+
|
|
367
|
+
<Accordion title=${JSON.stringify(relativePath)} variant="changed">
|
|
368
|
+
|
|
369
|
+
${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\n')}
|
|
370
|
+
|
|
371
|
+
</Accordion>
|
|
372
|
+
|
|
373
|
+
`);
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
case 'DeletedFile': {
|
|
377
|
+
markdownLines.push(`
|
|
378
|
+
<Accordion title=${JSON.stringify(relativePath)} variant="deleted">
|
|
379
|
+
|
|
380
|
+
${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\n')}
|
|
381
|
+
|
|
382
|
+
</Accordion>
|
|
383
|
+
`);
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
case 'RenamedFile': {
|
|
387
|
+
const relativeBefore = diffPathToRelative(file.pathBefore);
|
|
388
|
+
const relativeAfter = diffPathToRelative(file.pathAfter);
|
|
389
|
+
const title = JSON.stringify(`${relativeBefore} ▶️ ${relativeAfter}`);
|
|
390
|
+
markdownLines.push(`
|
|
391
|
+
<Accordion title=${title} variant="renamed">
|
|
392
|
+
|
|
393
|
+
${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\n')}
|
|
394
|
+
|
|
395
|
+
</Accordion>
|
|
396
|
+
`);
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
case 'AddedFile': {
|
|
400
|
+
markdownLines.push(`
|
|
401
|
+
<Accordion title=${JSON.stringify(relativePath)} variant="added">
|
|
402
|
+
|
|
403
|
+
${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\n')}
|
|
404
|
+
|
|
405
|
+
</Accordion>
|
|
406
|
+
`);
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
default: {
|
|
410
|
+
console.error(file);
|
|
411
|
+
throw new Error(`Unknown file type: ${file}`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const code = await compileMarkdownString(markdownLines.join('\n'));
|
|
416
|
+
return code;
|
|
417
|
+
}
|
|
418
|
+
export async function getDiffOutputWithRelativePaths(app1, app2) {
|
|
419
|
+
const { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2);
|
|
420
|
+
const { stdout: diffOutput } = await execa('git', [
|
|
421
|
+
'diff',
|
|
422
|
+
'--no-index',
|
|
423
|
+
app1CopyPath,
|
|
424
|
+
app2CopyPath,
|
|
425
|
+
'--color=never',
|
|
426
|
+
'--color-moved-ws=allow-indentation-change',
|
|
427
|
+
'--no-prefix',
|
|
428
|
+
'--ignore-blank-lines',
|
|
429
|
+
'--ignore-space-change',
|
|
430
|
+
], { cwd: diffTmpDir }).catch((e) => e);
|
|
431
|
+
void fsExtra.remove(app1CopyPath);
|
|
432
|
+
void fsExtra.remove(app2CopyPath);
|
|
433
|
+
return diffOutput
|
|
434
|
+
.replaceAll(app1CopyPath.slice(1), '.')
|
|
435
|
+
.replaceAll(app2CopyPath.slice(1), '.');
|
|
436
|
+
}
|
|
437
|
+
//# sourceMappingURL=diff.server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.server.js","sourceRoot":"","sources":["../../src/diff.server.ts"],"names":[],"mappings":"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","sourcesContent":["import os from 'os'\nimport path from 'path'\nimport { type CacheEntry } from '@epic-web/cachified'\nimport { execa } from 'execa'\nimport fsExtra from 'fs-extra'\nimport ignore from 'ignore'\nimport parseGitDiff, { type AnyFileChange } from 'parse-git-diff'\nimport { bundledLanguagesInfo } from 'shiki/langs'\nimport {\n\tgetForceFreshForDir,\n\tgetRelativePath,\n\tgetWorkshopRoot,\n\tmodifiedTimes,\n\ttype App,\n} from './apps.server.js'\nimport { cachified, diffCodeCache, diffFilesCache } from './cache.server.js'\nimport { compileMarkdownString } from './compile-mdx.server.js'\nimport { modifiedMoreRecentlyThan } from './modified-time.server.js'\nimport { type Timings } from './timing.server.js'\n\nconst epicshopTempDir = path.join(os.tmpdir(), 'epicshop')\n\nconst isDeployed = ENV.EPICSHOP_DEPLOYED\n\nconst diffTmpDir = path.join(epicshopTempDir, 'diff')\n\nfunction diffPathToRelative(filePath: string) {\n\tlet normalizedPath = path.normalize(filePath.replace(/^(\"|')|(\"|')$/g, ''))\n\tif (\n\t\tnormalizedPath.startsWith('a\\\\') ||\n\t\tnormalizedPath.startsWith('b\\\\') ||\n\t\tnormalizedPath.startsWith('a/') ||\n\t\tnormalizedPath.startsWith('b/')\n\t) {\n\t\tnormalizedPath = normalizedPath.slice(2)\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\tconst [workshopRootDirname, appId, id, ...relativePath] = normalizedPath\n\t\t.replace(\n\t\t\tprocess.platform === 'win32' || normalizedPath.startsWith(path.sep)\n\t\t\t\t? `${diffTmpDir}${path.sep}`\n\t\t\t\t: `${diffTmpDir.slice(1)}${path.sep}`,\n\t\t\t'',\n\t\t)\n\t\t.split(path.sep)\n\n\treturn relativePath.join(path.sep)\n}\n\nfunction getLanguage(ext: string) {\n\treturn (\n\t\tbundledLanguagesInfo.find((l) => l.id === ext || l.aliases?.includes(ext))\n\t\t\t?.id ?? 'text'\n\t)\n}\n\nfunction getFileCodeblocks(\n\tfile: ReturnType<typeof parseGitDiff>['files'][number],\n\tfilePathApp1: string,\n\tfilePathApp2: string,\n\ttype: string,\n) {\n\tif (!file.chunks.length) {\n\t\treturn [\n\t\t\t`<p className=\"m-0 p-4 border-b text-muted-foreground\">No changes</p>`,\n\t\t]\n\t}\n\tconst filepath = diffPathToRelative(\n\t\tfile.type === 'RenamedFile' ? file.pathAfter : file.path,\n\t)\n\tconst extension = path.extname(filepath).slice(1)\n\tconst lang = getLanguage(extension)\n\tconst pathToCopy = file.type === 'RenamedFile' ? file.pathBefore : file.path\n\tconst relativePath = diffPathToRelative(pathToCopy)\n\tconst markdownLines = []\n\tfor (const chunk of file.chunks) {\n\t\tconst removedLineNumbers = []\n\t\tconst addedLineNumbers = []\n\t\tconst lines = []\n\t\tlet toStartLine = 0\n\t\tlet startLine = 1\n\t\tif (chunk.type === 'BinaryFilesChunk') {\n\t\t\tlines.push(\n\t\t\t\ttype === 'AddedFile'\n\t\t\t\t\t? `Binary file added`\n\t\t\t\t\t: type === 'DeletedFile'\n\t\t\t\t\t\t? 'Binary file deleted'\n\t\t\t\t\t\t: 'Binary file changed',\n\t\t\t)\n\t\t} else {\n\t\t\tstartLine =\n\t\t\t\tchunk.type === 'Chunk'\n\t\t\t\t\t? chunk.fromFileRange.start\n\t\t\t\t\t: chunk.type === 'CombinedChunk'\n\t\t\t\t\t\t? chunk.fromFileRangeA.start\n\t\t\t\t\t\t: 1\n\t\t\ttoStartLine = chunk.toFileRange.start\n\t\t\tfor (\n\t\t\t\tlet lineNumber = 0;\n\t\t\t\tlineNumber < chunk.changes.length;\n\t\t\t\tlineNumber++\n\t\t\t) {\n\t\t\t\tconst change = chunk.changes[lineNumber]\n\t\t\t\tif (!change) continue\n\t\t\t\tlines.push(change.content)\n\t\t\t\tswitch (change.type) {\n\t\t\t\t\tcase 'AddedLine': {\n\t\t\t\t\t\taddedLineNumbers.push(startLine + lineNumber)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'DeletedLine': {\n\t\t\t\t\t\tremovedLineNumbers.push(startLine + lineNumber)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst params = [\n\t\t\t['filename', relativePath.replace(/\\\\/g, '\\\\\\\\')],\n\t\t\t['start', startLine.toString()],\n\t\t\tremovedLineNumbers.length\n\t\t\t\t? ['remove', removedLineNumbers.join(',')]\n\t\t\t\t: null,\n\t\t\taddedLineNumbers.length ? ['add', addedLineNumbers.join(',')] : null,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t\t.join(' ')\n\n\t\tconst launchEditorClassName =\n\t\t\t'border hover:bg-foreground/20 rounded px-2 py-0.5 font-mono text-xs font-semibold'\n\n\t\tfunction launchEditor(appNum: number, line: number) {\n\t\t\tif (isDeployed) {\n\t\t\t\tif (type === 'DeletedFile' && appNum === 2) return ''\n\t\t\t\tif (type === 'AddedFile' && appNum === 1) return ''\n\t\t\t}\n\n\t\t\tconst label =\n\t\t\t\t(type === 'AddedFile' && appNum === 1) ||\n\t\t\t\t(type === 'DeletedFile' && appNum === 2)\n\t\t\t\t\t? `CREATE in APP ${appNum}`\n\t\t\t\t\t: `OPEN in APP ${appNum}`\n\t\t\tconst file = JSON.stringify(appNum === 1 ? filePathApp1 : filePathApp2)\n\t\t\tconst fixedTitle = getRelativePath(file)\n\n\t\t\treturn `\n<LaunchEditor file=${file} line={${line}}>\n\t<span title=\"${fixedTitle}\" className=\"${launchEditorClassName}\">${label}</span>\n</LaunchEditor>`\n\t\t}\n\n\t\tmarkdownLines.push(`\n<div className=\"relative\">\n\n\\`\\`\\`${lang} ${params}\n${lines.join('\\n')}\n\\`\\`\\`\n\n<div className=\"flex gap-4 absolute top-1 right-3 items-center\">\n\t${launchEditor(1, startLine)}\n\t<div className=\"display-alt-down flex gap-2\">\n\t\t<LaunchEditor file=${JSON.stringify(\n\t\t\tfilePathApp1,\n\t\t)} syncTo={{file: ${JSON.stringify(filePathApp2)}}}>\n\t\t\t<span className=\"block ${launchEditorClassName}\">\n\t\t\t\t<Icon name=\"ArrowLeft\" title=\"Copy app 2 file to app 1\" />\n\t\t\t</span>\n\t\t</LaunchEditor>\n\t\t<LaunchEditor file=${JSON.stringify(\n\t\t\tfilePathApp2,\n\t\t)} syncTo={{file: ${JSON.stringify(filePathApp1)}}}>\n\t\t\t<span className=\"block ${launchEditorClassName}\">\n\t\t\t\t<Icon name=\"ArrowRight\" title=\"Copy app 1 file to app 2\" />\n\t\t\t</span>\n\t\t</LaunchEditor>\n\t</div>\n\t${launchEditor(2, toStartLine)}\n</div>\n\n</div>\n`)\n\t}\n\treturn markdownLines\n}\n\nconst DEFAULT_IGNORE_PATTERNS = [\n\t'**/README.*',\n\t'**/package-lock.json',\n\t'**/.DS_Store',\n\t'**/.vscode',\n\t'**/.idea',\n\t'**/.git',\n\t'**/*.db',\n\t'**/epicshop/**',\n]\n\nasync function copyUnignoredFiles(\n\tsrcDir: string,\n\tdestDir: string,\n\tignoreList: Array<string>,\n) {\n\tconst key = `COPY_${srcDir}__${destDir}__${ignoreList.join('_')}`\n\tawait cachified({\n\t\tkey,\n\t\tcache: diffCodeCache,\n\t\tforceFresh: getForceFreshForDir(diffCodeCache.get(key), srcDir),\n\t\tasync getFreshValue() {\n\t\t\t// @ts-ignore 🤷♂️ weird module stuff\n\t\t\tconst ig = ignore().add(ignoreList)\n\n\t\t\tawait fsExtra.remove(destDir)\n\t\t\tawait fsExtra.copy(srcDir, destDir, {\n\t\t\t\tfilter: async (file) => {\n\t\t\t\t\tif (file === srcDir) return true\n\t\t\t\t\treturn !ig.ignores(path.relative(srcDir, file))\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t})\n}\n\nasync function prepareForDiff(app1: App, app2: App) {\n\tconst id = Math.random().toString(36).slice(2)\n\tconst app1CopyPath = path.join(\n\t\tdiffTmpDir,\n\t\tpath.basename(getWorkshopRoot()),\n\t\tapp1.name,\n\t\tid,\n\t)\n\tconst app2CopyPath = path.join(\n\t\tdiffTmpDir,\n\t\tpath.basename(getWorkshopRoot()),\n\t\tapp2.name,\n\t\tid,\n\t)\n\t// if everything except the `name` property of the `package.json` is the same\n\t// the don't bother copying it\n\tconst comparePkgJson = (pkg1: any, pkg2: any) => {\n\t\tconst { name, ...rest1 } = pkg1\n\t\tconst { name: name2, ...rest2 } = pkg2\n\t\treturn JSON.stringify(rest1) === JSON.stringify(rest2)\n\t}\n\tconst app1PkgJson =\n\t\tapp1.dev.type === 'script'\n\t\t\t? await fsExtra\n\t\t\t\t\t.readJSON(path.join(app1.fullPath, 'package.json'))\n\t\t\t\t\t.catch(() => ({}))\n\t\t\t: {}\n\tconst app2PkgJson =\n\t\tapp1.dev.type === 'script'\n\t\t\t? await fsExtra\n\t\t\t\t\t.readJSON(path.join(app2.fullPath, 'package.json'))\n\t\t\t\t\t.catch(() => ({}))\n\t\t\t: {}\n\tconst pkgJsonIgnore: Array<string> = comparePkgJson(app1PkgJson, app2PkgJson)\n\t\t? ['package.json']\n\t\t: []\n\tconst workshopIgnore = [\n\t\t...(await getDiffIgnore(path.join(getWorkshopRoot(), '.gitignore'))),\n\t\t...(await getDiffIgnore(\n\t\t\tpath.join(getWorkshopRoot(), 'epicshop', '.diffignore'),\n\t\t)),\n\t]\n\n\tawait Promise.all([\n\t\tcopyUnignoredFiles(app1.fullPath, app1CopyPath, [\n\t\t\t...DEFAULT_IGNORE_PATTERNS,\n\t\t\t...pkgJsonIgnore,\n\t\t\t...workshopIgnore,\n\t\t\t...(await getDiffIgnore(path.join(app1.fullPath, '.gitignore'))),\n\t\t\t...(await getDiffIgnore(\n\t\t\t\tpath.join(app1.fullPath, 'epicshop', '.diffignore'),\n\t\t\t)),\n\t\t]),\n\t\tcopyUnignoredFiles(app2.fullPath, app2CopyPath, [\n\t\t\t...DEFAULT_IGNORE_PATTERNS,\n\t\t\t...pkgJsonIgnore,\n\t\t\t...workshopIgnore,\n\t\t\t...(await getDiffIgnore(path.join(app2.fullPath, '.gitignore'))),\n\t\t\t...(await getDiffIgnore(\n\t\t\t\tpath.join(app2.fullPath, 'epicshop', '.diffignore'),\n\t\t\t)),\n\t\t]),\n\t])\n\n\treturn { app1CopyPath, app2CopyPath }\n}\n\nasync function getDiffIgnore(filePath: string): Promise<Array<string>> {\n\treturn (await fsExtra.pathExists(filePath))\n\t\t? fsExtra.readFile(filePath, 'utf8').then((content) =>\n\t\t\t\tcontent\n\t\t\t\t\t.split('\\n')\n\t\t\t\t\t.map((line) => line.trim())\n\t\t\t\t\t.filter((line) => !line.startsWith('#'))\n\t\t\t\t\t.filter(Boolean),\n\t\t\t)\n\t\t: []\n}\n\nasync function getForceFreshForDiff(\n\tapp1: App,\n\tapp2: App,\n\tcacheEntry: CacheEntry | null | undefined,\n) {\n\t// don't know when the cache was created? force refresh\n\tconst cacheModified = cacheEntry?.metadata.createdTime\n\tif (!cacheModified) return true\n\n\t// app1 modified after cache? force refresh\n\tconst app1Modified = modifiedTimes.get(app1.fullPath) ?? 0\n\tif (app1Modified > cacheModified) return true\n\n\t// app2 modified after cache? force refresh\n\tconst app2Modified = modifiedTimes.get(app2.fullPath) ?? 0\n\tif (app2Modified > cacheModified) return true\n\n\t// ok, now let's actually check the modified times of all files in the\n\t// directories and as soon as we find a file that was modified more recently\n\t// then we know we need to force refresh\n\tconst modifiedMoreRecently = await modifiedMoreRecentlyThan(\n\t\tcacheModified,\n\t\tapp1.fullPath,\n\t\tapp2.fullPath,\n\t)\n\tif (modifiedMoreRecently) return true\n\n\treturn undefined\n}\n\nexport async function getDiffFiles(\n\tapp1: App,\n\tapp2: App,\n\t{\n\t\tforceFresh,\n\t\ttimings,\n\t\trequest,\n\t}: { forceFresh?: boolean; timings?: Timings; request?: Request } = {},\n) {\n\tconst key = `${app1.relativePath}__vs__${app2.relativePath}`\n\tconst cacheEntry = diffFilesCache.get(key)\n\tconst result = await cachified({\n\t\tkey,\n\t\tcache: diffFilesCache,\n\t\tforceFresh:\n\t\t\tforceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),\n\t\ttimings,\n\t\trequest,\n\t\tgetFreshValue: () => getDiffFilesImpl(app1, app2),\n\t})\n\treturn result\n}\n\nfunction getAppTestFiles(app: App) {\n\treturn app.test.type === 'browser' ? app.test.testFiles : []\n}\n\nasync function getDiffFilesImpl(app1: App, app2: App) {\n\tif (app1.name === app2.name) {\n\t\treturn []\n\t}\n\tconst { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2)\n\n\tconst { stdout: diffOutput } = await execa(\n\t\t'git',\n\t\t[\n\t\t\t'diff',\n\t\t\t'--no-index',\n\t\t\t'--ignore-blank-lines',\n\t\t\t'--ignore-space-change',\n\t\t\tapp1CopyPath,\n\t\t\tapp2CopyPath,\n\t\t],\n\t\t{ cwd: diffTmpDir },\n\t\t// --no-index implies --exit-code, so we need to use the error output\n\t).catch((e) => e as { stdout: string })\n\n\tvoid fsExtra.remove(app1CopyPath)\n\tvoid fsExtra.remove(app2CopyPath)\n\n\tconst typesMap = {\n\t\tChangedFile: 'modified',\n\t\tAddedFile: 'added',\n\t\tDeletedFile: 'deleted',\n\t\tRenamedFile: 'renamed',\n\t}\n\n\tconst parsed = parseGitDiff(diffOutput, { noPrefix: true })\n\n\tconst testFiles = Array.from(\n\t\tnew Set([...getAppTestFiles(app1), ...getAppTestFiles(app2)]),\n\t)\n\n\tconst startLine = (file: AnyFileChange) => {\n\t\tconst chunk = file.type === 'ChangedFile' && file.chunks[0]\n\t\tif (chunk) {\n\t\t\treturn chunk.type === 'Chunk'\n\t\t\t\t? chunk.fromFileRange.start\n\t\t\t\t: chunk.type === 'CombinedChunk'\n\t\t\t\t\t? chunk.fromFileRangeA.start\n\t\t\t\t\t: 1\n\t\t}\n\t\treturn 1\n\t}\n\n\treturn parsed.files\n\t\t.map((file) => ({\n\t\t\t// prettier-ignore\n\n\t\t\tstatus: (typesMap[file.type] ?? 'unknown') as 'renamed' | 'modified' | 'deleted' | 'added' | 'unknown',\n\t\t\tpath: diffPathToRelative(\n\t\t\t\tfile.type === 'RenamedFile' ? file.pathBefore : file.path,\n\t\t\t),\n\t\t\tline: startLine(file),\n\t\t}))\n\t\t.filter((file) => !testFiles.includes(file.path))\n}\n\nexport async function getDiffCode(\n\tapp1: App,\n\tapp2: App,\n\t{\n\t\tforceFresh,\n\t\ttimings,\n\t\trequest,\n\t}: { forceFresh?: boolean; timings?: Timings; request?: Request } = {},\n) {\n\tconst key = `${app1.relativePath}__vs__${app2.relativePath}`\n\tconst cacheEntry = diffCodeCache.get(key)\n\tconst result = await cachified({\n\t\tkey,\n\t\tcache: diffCodeCache,\n\t\tforceFresh:\n\t\t\tforceFresh || (await getForceFreshForDiff(app1, app2, cacheEntry)),\n\t\ttimings,\n\t\trequest,\n\t\tgetFreshValue: () => getDiffCodeImpl(app1, app2),\n\t})\n\treturn result\n}\n\nasync function getDiffCodeImpl(app1: App, app2: App) {\n\tconst markdownLines = ['']\n\n\tif (app1.name === app2.name) {\n\t\tmarkdownLines.push(\n\t\t\t'<p className=\"p-4 text-center\">You are comparing the same app</p>',\n\t\t)\n\t\tconst code = await compileMarkdownString(markdownLines.join('\\n'))\n\t\treturn code\n\t}\n\n\tconst { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2)\n\n\tconst { stdout: diffOutput } = await execa(\n\t\t'git',\n\t\t[\n\t\t\t'diff',\n\t\t\t'--no-index',\n\t\t\tapp1CopyPath,\n\t\t\tapp2CopyPath,\n\t\t\t'--color=never',\n\t\t\t'--color-moved-ws=allow-indentation-change',\n\t\t\t'--no-prefix',\n\t\t\t'--ignore-blank-lines',\n\t\t\t'--ignore-space-change',\n\t\t],\n\t\t{ cwd: diffTmpDir },\n\t\t// --no-index implies --exit-code, so we need to use the error output\n\t).catch((e) => e as { stdout: string })\n\n\tvoid fsExtra.remove(app1CopyPath)\n\tvoid fsExtra.remove(app2CopyPath)\n\n\tconst parsed = parseGitDiff(diffOutput)\n\n\tif (!parsed.files.length) {\n\t\tmarkdownLines.push(\n\t\t\t'<div className=\"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background\">No changes</div>',\n\t\t)\n\t}\n\n\tconst app1TestFiles = getAppTestFiles(app1)\n\tconst app2TestFiles = getAppTestFiles(app2)\n\n\tfor (const file of parsed.files) {\n\t\tconst pathToCopy = file.type === 'RenamedFile' ? file.pathBefore : file.path\n\t\tconst relativePath = diffPathToRelative(pathToCopy)\n\t\tif (app1TestFiles.includes(relativePath)) continue\n\t\tconst filePathApp1 = path.join(app1.fullPath, relativePath)\n\n\t\tconst pathToApp2 = file.type === 'RenamedFile' ? file.pathAfter : file.path\n\t\tconst relativePathApp2 = diffPathToRelative(pathToApp2)\n\t\tif (app2TestFiles.includes(relativePathApp2)) continue\n\t\tconst filePathApp2 = path.join(app2.fullPath, relativePathApp2)\n\n\t\tswitch (file.type) {\n\t\t\tcase 'ChangedFile': {\n\t\t\t\tmarkdownLines.push(`\n\n<Accordion title=${JSON.stringify(relativePath)} variant=\"changed\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'DeletedFile': {\n\t\t\t\tmarkdownLines.push(`\n<Accordion title=${JSON.stringify(relativePath)} variant=\"deleted\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'RenamedFile': {\n\t\t\t\tconst relativeBefore = diffPathToRelative(file.pathBefore)\n\t\t\t\tconst relativeAfter = diffPathToRelative(file.pathAfter)\n\t\t\t\tconst title = JSON.stringify(`${relativeBefore} ▶️ ${relativeAfter}`)\n\t\t\t\tmarkdownLines.push(`\n<Accordion title=${title} variant=\"renamed\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'AddedFile': {\n\t\t\t\tmarkdownLines.push(`\n<Accordion title=${JSON.stringify(relativePath)} variant=\"added\">\n\n${getFileCodeblocks(file, filePathApp1, filePathApp2, file.type).join('\\n')}\n\n</Accordion>\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tconsole.error(file)\n\t\t\t\tthrow new Error(`Unknown file type: ${file}`)\n\t\t\t}\n\t\t}\n\t}\n\tconst code = await compileMarkdownString(markdownLines.join('\\n'))\n\treturn code\n}\n\nexport async function getDiffOutputWithRelativePaths(app1: App, app2: App) {\n\tconst { app1CopyPath, app2CopyPath } = await prepareForDiff(app1, app2)\n\n\tconst { stdout: diffOutput } = await execa(\n\t\t'git',\n\t\t[\n\t\t\t'diff',\n\t\t\t'--no-index',\n\t\t\tapp1CopyPath,\n\t\t\tapp2CopyPath,\n\t\t\t'--color=never',\n\t\t\t'--color-moved-ws=allow-indentation-change',\n\t\t\t'--no-prefix',\n\t\t\t'--ignore-blank-lines',\n\t\t\t'--ignore-space-change',\n\t\t],\n\t\t{ cwd: diffTmpDir },\n\t\t// --no-index implies --exit-code, so we need to use the error output\n\t).catch((e) => e as { stdout: string })\n\n\tvoid fsExtra.remove(app1CopyPath)\n\tvoid fsExtra.remove(app2CopyPath)\n\n\treturn diffOutput\n\t\t.replaceAll(app1CopyPath.slice(1), '.')\n\t\t.replaceAll(app2CopyPath.slice(1), '.')\n}\n"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
declare const schema: z.ZodObject<{
|
|
3
|
+
NODE_ENV: z.ZodDefault<z.ZodEnum<["production", "development", "test"]>>;
|
|
4
|
+
EPICSHOP_GITHUB_REPO: z.ZodString;
|
|
5
|
+
EPICSHOP_GITHUB_ROOT: z.ZodString;
|
|
6
|
+
EPICSHOP_CONTEXT_CWD: z.ZodString;
|
|
7
|
+
EPICSHOP_APP_VERSION: z.ZodOptional<z.ZodString>;
|
|
8
|
+
EPICSHOP_PARENT_PORT: z.ZodOptional<z.ZodString>;
|
|
9
|
+
EPICSHOP_PARENT_TOKEN: z.ZodOptional<z.ZodString>;
|
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
NODE_ENV: "production" | "development" | "test";
|
|
12
|
+
EPICSHOP_GITHUB_REPO: string;
|
|
13
|
+
EPICSHOP_GITHUB_ROOT: string;
|
|
14
|
+
EPICSHOP_CONTEXT_CWD: string;
|
|
15
|
+
EPICSHOP_APP_VERSION?: string | undefined;
|
|
16
|
+
EPICSHOP_PARENT_PORT?: string | undefined;
|
|
17
|
+
EPICSHOP_PARENT_TOKEN?: string | undefined;
|
|
18
|
+
}, {
|
|
19
|
+
EPICSHOP_GITHUB_REPO: string;
|
|
20
|
+
EPICSHOP_GITHUB_ROOT: string;
|
|
21
|
+
EPICSHOP_CONTEXT_CWD: string;
|
|
22
|
+
NODE_ENV?: "production" | "development" | "test" | undefined;
|
|
23
|
+
EPICSHOP_APP_VERSION?: string | undefined;
|
|
24
|
+
EPICSHOP_PARENT_PORT?: string | undefined;
|
|
25
|
+
EPICSHOP_PARENT_TOKEN?: string | undefined;
|
|
26
|
+
}>;
|
|
27
|
+
declare global {
|
|
28
|
+
namespace NodeJS {
|
|
29
|
+
interface ProcessEnv extends z.infer<typeof schema> {
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export declare function init(): void;
|
|
34
|
+
/**
|
|
35
|
+
* This is used in both `entry.server.ts` and `root.tsx` to ensure that
|
|
36
|
+
* the environment variables are set and globally available before the app is
|
|
37
|
+
* started.
|
|
38
|
+
*
|
|
39
|
+
* NOTE: Do *not* add any environment variables in here that you do not wish to
|
|
40
|
+
* be included in the client.
|
|
41
|
+
* @returns all public ENV variables
|
|
42
|
+
*/
|
|
43
|
+
export declare function getEnv(): {
|
|
44
|
+
MODE: "production" | "development" | "test";
|
|
45
|
+
EPICSHOP_CONTEXT_CWD: string;
|
|
46
|
+
EPICSHOP_GITHUB_REPO: string;
|
|
47
|
+
EPICSHOP_GITHUB_ROOT: string;
|
|
48
|
+
EPICSHOP_DEPLOYED: boolean;
|
|
49
|
+
EPICSHOP_APP_VERSION: string | undefined;
|
|
50
|
+
EPICSHOP_PARENT_PORT: string | undefined;
|
|
51
|
+
EPICSHOP_PARENT_TOKEN: string | undefined;
|
|
52
|
+
};
|
|
53
|
+
type ENV = ReturnType<typeof getEnv>;
|
|
54
|
+
declare global {
|
|
55
|
+
var ENV: ENV;
|
|
56
|
+
interface Window {
|
|
57
|
+
ENV: ENV;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=env.server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.server.d.ts","sourceRoot":"","sources":["../../src/env.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;EAUV,CAAA;AAEF,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM,CAAC;QAChB,UAAU,UAAW,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC;SAAG;KACtD;CACD;AAED,wBAAgB,IAAI,SAWnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM;;;;;;;;;EAarB;AAED,KAAK,GAAG,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAA;AAEpC,OAAO,CAAC,MAAM,CAAC;IACd,IAAI,GAAG,EAAE,GAAG,CAAA;IACZ,UAAU,MAAM;QACf,GAAG,EAAE,GAAG,CAAA;KACR;CACD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const schema = z.object({
|
|
3
|
+
NODE_ENV: z
|
|
4
|
+
.enum(['production', 'development', 'test'])
|
|
5
|
+
.default('development'),
|
|
6
|
+
EPICSHOP_GITHUB_REPO: z.string(),
|
|
7
|
+
EPICSHOP_GITHUB_ROOT: z.string(),
|
|
8
|
+
EPICSHOP_CONTEXT_CWD: z.string(),
|
|
9
|
+
EPICSHOP_APP_VERSION: z.string().optional(),
|
|
10
|
+
EPICSHOP_PARENT_PORT: z.string().optional(),
|
|
11
|
+
EPICSHOP_PARENT_TOKEN: z.string().optional(),
|
|
12
|
+
});
|
|
13
|
+
export function init() {
|
|
14
|
+
const parsed = schema.safeParse(process.env);
|
|
15
|
+
if (!parsed.success) {
|
|
16
|
+
console.error('❌ Invalid environment variables:', parsed.error.flatten().fieldErrors);
|
|
17
|
+
throw new Error('Invalid environment variables');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* This is used in both `entry.server.ts` and `root.tsx` to ensure that
|
|
22
|
+
* the environment variables are set and globally available before the app is
|
|
23
|
+
* started.
|
|
24
|
+
*
|
|
25
|
+
* NOTE: Do *not* add any environment variables in here that you do not wish to
|
|
26
|
+
* be included in the client.
|
|
27
|
+
* @returns all public ENV variables
|
|
28
|
+
*/
|
|
29
|
+
export function getEnv() {
|
|
30
|
+
return {
|
|
31
|
+
MODE: process.env.NODE_ENV,
|
|
32
|
+
EPICSHOP_CONTEXT_CWD: process.env.EPICSHOP_CONTEXT_CWD,
|
|
33
|
+
EPICSHOP_GITHUB_REPO: process.env.EPICSHOP_GITHUB_REPO,
|
|
34
|
+
EPICSHOP_GITHUB_ROOT: process.env.EPICSHOP_GITHUB_ROOT,
|
|
35
|
+
EPICSHOP_DEPLOYED: process.env.EPICSHOP_DEPLOYED === 'true' ||
|
|
36
|
+
process.env.EPICSHOP_DEPLOYED === '1',
|
|
37
|
+
EPICSHOP_APP_VERSION: process.env.EPICSHOP_APP_VERSION,
|
|
38
|
+
EPICSHOP_PARENT_PORT: process.env.EPICSHOP_PARENT_PORT,
|
|
39
|
+
EPICSHOP_PARENT_TOKEN: process.env.EPICSHOP_PARENT_TOKEN,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=env.server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.server.js","sourceRoot":"","sources":["../../src/env.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACvB,QAAQ,EAAE,CAAC;SACT,IAAI,CAAC,CAAC,YAAY,EAAE,aAAa,EAAE,MAAM,CAAU,CAAC;SACpD,OAAO,CAAC,aAAa,CAAC;IACxB,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE;IAChC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE;IAChC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE;IAChC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3C,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3C,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5C,CAAC,CAAA;AAQF,MAAM,UAAU,IAAI;IACnB,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAE5C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACrB,OAAO,CAAC,KAAK,CACZ,kCAAkC,EAClC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,WAAW,CAClC,CAAA;QAED,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;IACjD,CAAC;AACF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,MAAM;IACrB,OAAO;QACN,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ;QAC1B,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACtD,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACtD,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACtD,iBAAiB,EAChB,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM;YACxC,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,GAAG;QACtC,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACtD,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACtD,qBAAqB,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB;KACxD,CAAA;AACF,CAAC","sourcesContent":["import { z } from 'zod'\n\nconst schema = z.object({\n\tNODE_ENV: z\n\t\t.enum(['production', 'development', 'test'] as const)\n\t\t.default('development'),\n\tEPICSHOP_GITHUB_REPO: z.string(),\n\tEPICSHOP_GITHUB_ROOT: z.string(),\n\tEPICSHOP_CONTEXT_CWD: z.string(),\n\tEPICSHOP_APP_VERSION: z.string().optional(),\n\tEPICSHOP_PARENT_PORT: z.string().optional(),\n\tEPICSHOP_PARENT_TOKEN: z.string().optional(),\n})\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv extends z.infer<typeof schema> {}\n\t}\n}\n\nexport function init() {\n\tconst parsed = schema.safeParse(process.env)\n\n\tif (!parsed.success) {\n\t\tconsole.error(\n\t\t\t'❌ Invalid environment variables:',\n\t\t\tparsed.error.flatten().fieldErrors,\n\t\t)\n\n\t\tthrow new Error('Invalid environment variables')\n\t}\n}\n\n/**\n * This is used in both `entry.server.ts` and `root.tsx` to ensure that\n * the environment variables are set and globally available before the app is\n * started.\n *\n * NOTE: Do *not* add any environment variables in here that you do not wish to\n * be included in the client.\n * @returns all public ENV variables\n */\nexport function getEnv() {\n\treturn {\n\t\tMODE: process.env.NODE_ENV,\n\t\tEPICSHOP_CONTEXT_CWD: process.env.EPICSHOP_CONTEXT_CWD,\n\t\tEPICSHOP_GITHUB_REPO: process.env.EPICSHOP_GITHUB_REPO,\n\t\tEPICSHOP_GITHUB_ROOT: process.env.EPICSHOP_GITHUB_ROOT,\n\t\tEPICSHOP_DEPLOYED:\n\t\t\tprocess.env.EPICSHOP_DEPLOYED === 'true' ||\n\t\t\tprocess.env.EPICSHOP_DEPLOYED === '1',\n\t\tEPICSHOP_APP_VERSION: process.env.EPICSHOP_APP_VERSION,\n\t\tEPICSHOP_PARENT_PORT: process.env.EPICSHOP_PARENT_PORT,\n\t\tEPICSHOP_PARENT_TOKEN: process.env.EPICSHOP_PARENT_TOKEN,\n\t}\n}\n\ntype ENV = ReturnType<typeof getEnv>\n\ndeclare global {\n\tvar ENV: ENV\n\tinterface Window {\n\t\tENV: ENV\n\t}\n}\n"]}
|