@epic-web/workshop-utils 5.0.1 → 5.0.3
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/dist/esm/apps.server.d.ts +9 -2
- package/dist/esm/apps.server.d.ts.map +1 -1
- package/dist/esm/apps.server.js +261 -188
- package/dist/esm/apps.server.js.map +1 -1
- package/dist/esm/cache.server.d.ts +6 -0
- package/dist/esm/cache.server.d.ts.map +1 -1
- package/dist/esm/cache.server.js +1 -0
- package/dist/esm/cache.server.js.map +1 -1
- package/dist/esm/config.server.d.ts +9 -10
- package/dist/esm/config.server.d.ts.map +1 -1
- package/dist/esm/config.server.js +11 -7
- package/dist/esm/config.server.js.map +1 -1
- 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/package.json +9 -9
- package/dist/esm/change-tracker.server.d.ts +0 -9
- package/dist/esm/change-tracker.server.d.ts.map +0 -1
- package/dist/esm/change-tracker.server.js +0 -80
- package/dist/esm/change-tracker.server.js.map +0 -1
|
@@ -2,6 +2,9 @@ import { type CacheEntry } from '@epic-web/cachified';
|
|
|
2
2
|
import '@total-typescript/ts-reset';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { type Timings } from './timing.server.js';
|
|
5
|
+
declare global {
|
|
6
|
+
var __epicshop_apps_initialized__: boolean | undefined;
|
|
7
|
+
}
|
|
5
8
|
export declare const workshopRoot: string;
|
|
6
9
|
type CachifiedOptions = {
|
|
7
10
|
timings?: Timings;
|
|
@@ -3138,8 +3141,8 @@ export declare function isPlaygroundApp(app: any): app is PlaygroundApp;
|
|
|
3138
3141
|
export declare function isExampleApp(app: any): app is ExampleApp;
|
|
3139
3142
|
export declare function isExerciseStepApp(app: any): app is ExerciseStepApp;
|
|
3140
3143
|
export declare const modifiedTimes: Map<string, number>;
|
|
3141
|
-
export declare function init(): void
|
|
3142
|
-
export declare function
|
|
3144
|
+
export declare function init(): Promise<void>;
|
|
3145
|
+
export declare function setModifiedTimesForAppDirs(...filePaths: Array<string>): void;
|
|
3143
3146
|
export declare function getForceFreshForDir(cacheEntry: CacheEntry | null | undefined, ...dirs: Array<string | undefined | null>): true | undefined;
|
|
3144
3147
|
export declare function getExercises({ timings, request, }?: CachifiedOptions): Promise<Array<Exercise>>;
|
|
3145
3148
|
export declare function getApps({ timings, request, forceFresh, }?: CachifiedOptions & {
|
|
@@ -4179,5 +4182,9 @@ export declare function getWorkshopFinished({ request, }?: {
|
|
|
4179
4182
|
readonly relativePath: "exercises/finished.mdx";
|
|
4180
4183
|
}>;
|
|
4181
4184
|
export declare function getRelativePath(filePath: string): string;
|
|
4185
|
+
/**
|
|
4186
|
+
* Given a file path, this will determine the path to the app that file belongs to.
|
|
4187
|
+
*/
|
|
4188
|
+
export declare function getAppPathFromFilePath(filePath: string): string | null;
|
|
4182
4189
|
export {};
|
|
4183
4190
|
//# sourceMappingURL=apps.server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.server.d.ts","sourceRoot":"","sources":["../../src/apps.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"apps.server.d.ts","sourceRoot":"","sources":["../../src/apps.server.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/apps.server.js
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { remember } from '@epic-web/remember';
|
|
4
|
+
import chokidar from 'chokidar';
|
|
4
5
|
/// TODO: figure out why this import is necessary (without it tsc seems to not honor the boolean reset 🤷♂️)
|
|
5
6
|
import '@total-typescript/ts-reset';
|
|
7
|
+
import closeWithGrace from 'close-with-grace';
|
|
6
8
|
import { execa } from 'execa';
|
|
7
9
|
import fsExtra from 'fs-extra';
|
|
8
|
-
import { glob } from 'glob';
|
|
9
10
|
import { globby, isGitIgnored } from 'globby';
|
|
10
11
|
import { z } from 'zod';
|
|
11
12
|
import { appsCache, cachified, exampleAppCache, playgroundAppCache, problemAppCache, solutionAppCache, } from './cache.server.js';
|
|
12
|
-
import { getWatcher, withoutWatcher } from './change-tracker.server.js';
|
|
13
13
|
import { compileMdx } from './compile-mdx.server.js';
|
|
14
|
-
import {
|
|
14
|
+
import { getAppConfig, getStackBlitzUrl, getWorkshopConfig, } from './config.server.js';
|
|
15
15
|
import { getEnv, init as initEnv } from './env.server.js';
|
|
16
|
+
import { getDirModifiedTime } from './modified-time.server.js';
|
|
16
17
|
import { closeProcess, isAppRunning, runAppDev, waitOnApp, } from './process-manager.server.js';
|
|
17
|
-
import { getServerTimeHeader } from './timing.server.js';
|
|
18
|
+
import { getServerTimeHeader, time } from './timing.server.js';
|
|
18
19
|
import { getErrorMessage } from './utils.js';
|
|
19
|
-
|
|
20
|
+
global.__epicshop_apps_initialized__ ??= false;
|
|
20
21
|
export const workshopRoot = (process.env.EPICSHOP_CONTEXT_CWD =
|
|
21
22
|
process.env.EPICSHOP_CONTEXT_CWD ?? process.cwd());
|
|
22
23
|
const playgroundAppNameInfoPath = path.join(workshopRoot, 'node_modules', '.cache', 'epicshop', 'playground.json');
|
|
@@ -141,27 +142,54 @@ async function firstToExist(...files) {
|
|
|
141
142
|
return index === -1 ? null : files[index];
|
|
142
143
|
}
|
|
143
144
|
export const modifiedTimes = remember('modified_times', () => new Map());
|
|
144
|
-
export function init() {
|
|
145
|
-
if (
|
|
145
|
+
export async function init() {
|
|
146
|
+
if (global.__epicshop_apps_initialized__)
|
|
146
147
|
return;
|
|
147
|
-
|
|
148
|
+
global.__epicshop_apps_initialized__ = true;
|
|
148
149
|
const config = getWorkshopConfig();
|
|
149
150
|
process.env.EPICSHOP_GITHUB_REPO = config.githubRepo;
|
|
150
151
|
process.env.EPICSHOP_GITHUB_ROOT = config.githubRoot;
|
|
151
152
|
initEnv();
|
|
152
153
|
global.ENV = getEnv();
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
154
|
+
if (!ENV.EPICSHOP_DEPLOYED &&
|
|
155
|
+
process.env.EPICSHOP_ENABLE_WATCHER === 'true') {
|
|
156
|
+
const isIgnored = await isGitIgnored({ cwd: workshopRoot });
|
|
157
|
+
// watch the README, FINISHED, and package.json for changes that affect the apps
|
|
158
|
+
const filesToWatch = ['README.mdx', 'FINISHED.mdx', 'package.json'];
|
|
159
|
+
const chok = chokidar.watch(['examples', 'playground', 'exercises'], {
|
|
160
|
+
cwd: workshopRoot,
|
|
161
|
+
ignoreInitial: true,
|
|
162
|
+
ignored(filePath, stats) {
|
|
163
|
+
if (isIgnored(filePath))
|
|
164
|
+
return true;
|
|
165
|
+
if (filePath.includes('.git'))
|
|
166
|
+
return true;
|
|
167
|
+
if (stats?.isDirectory()) {
|
|
168
|
+
if (filePath.endsWith('playground'))
|
|
169
|
+
return false;
|
|
170
|
+
const pathParts = filePath.split(path.sep);
|
|
171
|
+
if (pathParts.at(-2) === 'examples')
|
|
172
|
+
return false;
|
|
173
|
+
// steps
|
|
174
|
+
if (pathParts.at(-3) === 'exercises')
|
|
175
|
+
return false;
|
|
176
|
+
// exercises
|
|
177
|
+
if (pathParts.at(-2) === 'exercises')
|
|
178
|
+
return false;
|
|
179
|
+
// the exercise dir itself
|
|
180
|
+
if (pathParts.at(-1) === 'exercises')
|
|
181
|
+
return false;
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
return stats?.isFile()
|
|
185
|
+
? !filesToWatch.some((file) => filePath.endsWith(file))
|
|
186
|
+
: false;
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
chok.on('all', (_event, filePath) => {
|
|
190
|
+
setModifiedTimesForAppDirs(path.join(workshopRoot, filePath));
|
|
191
|
+
});
|
|
192
|
+
closeWithGrace(() => chok.close());
|
|
165
193
|
}
|
|
166
194
|
}
|
|
167
195
|
function getForceFresh(cacheEntry) {
|
|
@@ -172,8 +200,17 @@ function getForceFresh(cacheEntry) {
|
|
|
172
200
|
return undefined;
|
|
173
201
|
return latestModifiedTime > cacheEntry.metadata.createdTime ? true : undefined;
|
|
174
202
|
}
|
|
175
|
-
export function
|
|
176
|
-
|
|
203
|
+
export function setModifiedTimesForAppDirs(...filePaths) {
|
|
204
|
+
const now = Date.now();
|
|
205
|
+
for (const filePath of filePaths) {
|
|
206
|
+
const appDir = getAppPathFromFilePath(filePath);
|
|
207
|
+
if (appDir) {
|
|
208
|
+
modifiedTimes.set(appDir, now);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
console.warn(`filePath ${filePath} does not match any app dir`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
177
214
|
}
|
|
178
215
|
export function getForceFreshForDir(cacheEntry, ...dirs) {
|
|
179
216
|
const truthyDirs = dirs.filter(Boolean);
|
|
@@ -275,8 +312,7 @@ export async function getExercises({ timings, request, } = {}) {
|
|
|
275
312
|
}
|
|
276
313
|
let appCallCount = 0;
|
|
277
314
|
export async function getApps({ timings, request, forceFresh, } = {}) {
|
|
278
|
-
|
|
279
|
-
init();
|
|
315
|
+
await init();
|
|
280
316
|
const key = 'apps';
|
|
281
317
|
const apps = await cachified({
|
|
282
318
|
key,
|
|
@@ -289,10 +325,24 @@ export async function getApps({ timings, request, forceFresh, } = {}) {
|
|
|
289
325
|
ttl: 1000 * 60 * 60 * 24,
|
|
290
326
|
forceFresh: forceFresh ?? getForceFresh(appsCache.get(key)),
|
|
291
327
|
getFreshValue: async () => {
|
|
292
|
-
const playgroundApp = await
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
328
|
+
const [playgroundApp, problemApps, solutionApps, exampleApps] = await Promise.all([
|
|
329
|
+
time(() => getPlaygroundApp({ request, timings }), {
|
|
330
|
+
type: 'getPlaygroundApp',
|
|
331
|
+
timings,
|
|
332
|
+
}),
|
|
333
|
+
time(() => getProblemApps({ request, timings }), {
|
|
334
|
+
type: 'getProblemApps',
|
|
335
|
+
timings,
|
|
336
|
+
}),
|
|
337
|
+
time(() => getSolutionApps({ request, timings }), {
|
|
338
|
+
type: 'getSolutionApps',
|
|
339
|
+
timings,
|
|
340
|
+
}),
|
|
341
|
+
time(() => getExampleApps({ request, timings }), {
|
|
342
|
+
type: 'getExampleApps',
|
|
343
|
+
timings,
|
|
344
|
+
}),
|
|
345
|
+
]);
|
|
296
346
|
const sortedApps = [
|
|
297
347
|
playgroundApp,
|
|
298
348
|
...problemApps,
|
|
@@ -389,18 +439,38 @@ export function extractNumbersAndTypeFromAppNameOrPath(fullPathOrAppName) {
|
|
|
389
439
|
}
|
|
390
440
|
async function getProblemDirs() {
|
|
391
441
|
const exercisesDir = path.join(workshopRoot, 'exercises');
|
|
392
|
-
const problemDirs =
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
442
|
+
const problemDirs = [];
|
|
443
|
+
const exerciseSubDirs = await readDir(exercisesDir);
|
|
444
|
+
for (const subDir of exerciseSubDirs) {
|
|
445
|
+
const fullSubDir = path.join(exercisesDir, subDir);
|
|
446
|
+
// catch handles non-directories without us having to bother checking
|
|
447
|
+
// whether it's a directory
|
|
448
|
+
const subDirContents = await readDir(fullSubDir).catch(() => null);
|
|
449
|
+
if (!subDirContents)
|
|
450
|
+
continue;
|
|
451
|
+
const problemSubDirs = subDirContents
|
|
452
|
+
.filter((dir) => dir.includes('.problem'))
|
|
453
|
+
.map((dir) => path.join(fullSubDir, dir));
|
|
454
|
+
problemDirs.push(...problemSubDirs);
|
|
455
|
+
}
|
|
396
456
|
return problemDirs;
|
|
397
457
|
}
|
|
398
458
|
async function getSolutionDirs() {
|
|
399
459
|
const exercisesDir = path.join(workshopRoot, 'exercises');
|
|
400
|
-
const solutionDirs =
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
460
|
+
const solutionDirs = [];
|
|
461
|
+
const exerciseSubDirs = await readDir(exercisesDir);
|
|
462
|
+
for (const subDir of exerciseSubDirs) {
|
|
463
|
+
const fullSubDir = path.join(exercisesDir, subDir);
|
|
464
|
+
// catch handles non-directories without us having to bother checking
|
|
465
|
+
// whether it's a directory
|
|
466
|
+
const subDirContents = await readDir(fullSubDir).catch(() => null);
|
|
467
|
+
if (!subDirContents)
|
|
468
|
+
continue;
|
|
469
|
+
const solutionSubDirs = subDirContents
|
|
470
|
+
.filter((dir) => dir.includes('.solution'))
|
|
471
|
+
.map((dir) => path.join(fullSubDir, dir));
|
|
472
|
+
solutionDirs.push(...solutionSubDirs);
|
|
473
|
+
}
|
|
404
474
|
return solutionDirs;
|
|
405
475
|
}
|
|
406
476
|
/**
|
|
@@ -622,7 +692,7 @@ async function getExampleAppFromPath(fullPath, index, request) {
|
|
|
622
692
|
}
|
|
623
693
|
async function getExampleApps({ timings, request, } = {}) {
|
|
624
694
|
const examplesDir = path.join(workshopRoot, 'examples');
|
|
625
|
-
const exampleDirs = (await
|
|
695
|
+
const exampleDirs = (await readDir(examplesDir)).map((p) => path.join(examplesDir, p));
|
|
626
696
|
const exampleApps = [];
|
|
627
697
|
for (const exampleDir of exampleDirs) {
|
|
628
698
|
const index = exampleDirs.indexOf(exampleDir);
|
|
@@ -635,10 +705,12 @@ async function getExampleApps({ timings, request, } = {}) {
|
|
|
635
705
|
timingKey: exampleDir.replace(`${examplesDir}${path.sep}`, ''),
|
|
636
706
|
request,
|
|
637
707
|
forceFresh: getForceFreshForDir(exampleAppCache.get(key), exampleDir),
|
|
638
|
-
getFreshValue:
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
708
|
+
getFreshValue: async () => {
|
|
709
|
+
return getExampleAppFromPath(exampleDir, index, request).catch((error) => {
|
|
710
|
+
console.error(error);
|
|
711
|
+
return null;
|
|
712
|
+
});
|
|
713
|
+
},
|
|
642
714
|
});
|
|
643
715
|
if (exampleApp)
|
|
644
716
|
exampleApps.push(exampleApp);
|
|
@@ -701,10 +773,12 @@ async function getSolutionApps({ timings, request, } = {}) {
|
|
|
701
773
|
request,
|
|
702
774
|
ttl: 1000 * 60 * 60 * 24,
|
|
703
775
|
forceFresh: getForceFreshForDir(solutionAppCache.get(solutionDir), solutionDir),
|
|
704
|
-
getFreshValue:
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
776
|
+
getFreshValue: async () => {
|
|
777
|
+
return getSolutionAppFromPath(solutionDir, request).catch((error) => {
|
|
778
|
+
console.error(error);
|
|
779
|
+
return null;
|
|
780
|
+
});
|
|
781
|
+
},
|
|
708
782
|
});
|
|
709
783
|
if (solutionApp)
|
|
710
784
|
solutionApps.push(solutionApp);
|
|
@@ -768,10 +842,12 @@ async function getProblemApps({ timings, request, } = {}) {
|
|
|
768
842
|
request,
|
|
769
843
|
ttl: 1000 * 60 * 60 * 24,
|
|
770
844
|
forceFresh: getForceFreshForDir(problemAppCache.get(problemDir), problemDir, solutionDir),
|
|
771
|
-
getFreshValue:
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
845
|
+
getFreshValue: async () => {
|
|
846
|
+
return getProblemAppFromPath(problemDir).catch((error) => {
|
|
847
|
+
console.error(error);
|
|
848
|
+
return null;
|
|
849
|
+
});
|
|
850
|
+
},
|
|
775
851
|
});
|
|
776
852
|
if (problemApp)
|
|
777
853
|
problemApps.push(problemApp);
|
|
@@ -868,125 +944,121 @@ export async function getAppFromFile(filePath) {
|
|
|
868
944
|
}
|
|
869
945
|
export async function setPlayground(srcDir, { reset } = {}) {
|
|
870
946
|
const destDir = path.join(workshopRoot, 'playground');
|
|
871
|
-
await
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
947
|
+
const isIgnored = await isGitIgnored({ cwd: srcDir });
|
|
948
|
+
const playgroundApp = await getAppByName('playground');
|
|
949
|
+
const playgroundWasRunning = playgroundApp
|
|
950
|
+
? isAppRunning(playgroundApp)
|
|
951
|
+
: false;
|
|
952
|
+
if (playgroundApp && reset) {
|
|
953
|
+
await closeProcess(playgroundApp.name);
|
|
954
|
+
await fsExtra.remove(destDir);
|
|
955
|
+
}
|
|
956
|
+
const setPlaygroundTimestamp = Date.now();
|
|
957
|
+
// run prepare-playground script if it exists
|
|
958
|
+
const preSetPlaygroundPath = await firstToExist(path.join(srcDir, 'epicshop', 'pre-set-playground.js'), path.join(workshopRoot, 'epicshop', 'pre-set-playground.js'));
|
|
959
|
+
if (preSetPlaygroundPath) {
|
|
960
|
+
await execa('node', [preSetPlaygroundPath], {
|
|
961
|
+
cwd: workshopRoot,
|
|
962
|
+
stdio: 'inherit',
|
|
963
|
+
env: {
|
|
964
|
+
EPICSHOP_PLAYGROUND_TIMESTAMP: setPlaygroundTimestamp.toString(),
|
|
965
|
+
EPICSHOP_PLAYGROUND_DEST_DIR: destDir,
|
|
966
|
+
EPICSHOP_PLAYGROUND_SRC_DIR: srcDir,
|
|
967
|
+
EPICSHOP_PLAYGROUND_WAS_RUNNING: playgroundWasRunning.toString(),
|
|
968
|
+
},
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
const basename = path.basename(srcDir);
|
|
972
|
+
// If we don't delete the destination node_modules first then copying the new
|
|
973
|
+
// node_modules has issues.
|
|
974
|
+
await fsExtra.remove(path.join(destDir, 'node_modules'));
|
|
975
|
+
// Copy the contents of the source directory to the destination directory recursively
|
|
976
|
+
await fsExtra.copy(srcDir, destDir, {
|
|
977
|
+
filter: async (srcFile, destFile) => {
|
|
978
|
+
if (srcFile.includes(`${basename}${path.sep}build`) ||
|
|
979
|
+
srcFile.includes(`${basename}${path.sep}public${path.sep}build`)) {
|
|
980
|
+
return false;
|
|
981
|
+
}
|
|
982
|
+
if (srcFile === srcDir)
|
|
983
|
+
return true;
|
|
984
|
+
// we copy node_modules even though it's .gitignored
|
|
985
|
+
if (srcFile.includes('node_modules'))
|
|
986
|
+
return true;
|
|
987
|
+
// make sure .env is copied whether it's .gitignored or not
|
|
988
|
+
if (srcFile.endsWith('.env'))
|
|
989
|
+
return true;
|
|
990
|
+
if (isIgnored(srcFile))
|
|
991
|
+
return false;
|
|
992
|
+
try {
|
|
993
|
+
const isDir = (await fsExtra.stat(srcFile)).isDirectory();
|
|
994
|
+
if (isDir)
|
|
911
995
|
return true;
|
|
912
|
-
|
|
913
|
-
|
|
996
|
+
const destIsDir = (await fsExtra.stat(destFile)).isDirectory();
|
|
997
|
+
// weird, but ok
|
|
998
|
+
if (destIsDir)
|
|
914
999
|
return true;
|
|
915
|
-
if
|
|
1000
|
+
// it's better to check if the contents are the same before copying
|
|
1001
|
+
// because it avoids unnecessary writes and reduces the impact on any
|
|
1002
|
+
// file watchers (like the remix dev server). In practice, it's definitely
|
|
1003
|
+
// slower, but it's better because it doesn't cause the dev server to
|
|
1004
|
+
// crash as often.
|
|
1005
|
+
const currentContents = await fsExtra.readFile(destFile);
|
|
1006
|
+
const newContents = await fsExtra.readFile(srcFile);
|
|
1007
|
+
if (currentContents.equals(newContents))
|
|
916
1008
|
return false;
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1009
|
+
return true;
|
|
1010
|
+
}
|
|
1011
|
+
catch {
|
|
1012
|
+
// 🤷♂️ should probably copy it in this case
|
|
1013
|
+
return true;
|
|
1014
|
+
}
|
|
1015
|
+
},
|
|
1016
|
+
});
|
|
1017
|
+
async function getFiles(dir) {
|
|
1018
|
+
// make globby friendly to windows
|
|
1019
|
+
const dirPath = dir.replace(/\\/g, '/');
|
|
1020
|
+
const files = await globby([`${dirPath}/**/*`, '!**/build/**/*'], {
|
|
1021
|
+
onlyFiles: false,
|
|
1022
|
+
dot: true,
|
|
1023
|
+
});
|
|
1024
|
+
return files.map((f) => f.replace(dirPath, ''));
|
|
1025
|
+
}
|
|
1026
|
+
// Remove files from destDir that were in destDir before but are not in srcDir
|
|
1027
|
+
const srcFiles = await getFiles(srcDir);
|
|
1028
|
+
const destFiles = await getFiles(destDir);
|
|
1029
|
+
const filesToDelete = destFiles.filter((fileName) => !srcFiles.includes(fileName));
|
|
1030
|
+
for (const fileToDelete of filesToDelete) {
|
|
1031
|
+
await fsExtra.remove(path.join(destDir, fileToDelete));
|
|
1032
|
+
}
|
|
1033
|
+
const appName = getAppName(srcDir);
|
|
1034
|
+
await fsExtra.ensureDir(path.dirname(playgroundAppNameInfoPath));
|
|
1035
|
+
await fsExtra.writeJSON(playgroundAppNameInfoPath, { appName });
|
|
1036
|
+
const playgroundIsStillRunning = playgroundApp
|
|
1037
|
+
? isAppRunning(playgroundApp)
|
|
1038
|
+
: false;
|
|
1039
|
+
const restartPlayground = playgroundWasRunning && !playgroundIsStillRunning;
|
|
1040
|
+
// run postSet-playground script if it exists
|
|
1041
|
+
const postSetPlaygroundPath = await firstToExist(path.join(srcDir, 'epicshop', 'post-set-playground.js'), path.join(workshopRoot, 'epicshop', 'post-set-playground.js'));
|
|
1042
|
+
if (postSetPlaygroundPath) {
|
|
1043
|
+
await execa('node', [postSetPlaygroundPath], {
|
|
1044
|
+
cwd: workshopRoot,
|
|
1045
|
+
stdio: 'inherit',
|
|
1046
|
+
env: {
|
|
1047
|
+
EPICSHOP_PLAYGROUND_TIMESTAMP: setPlaygroundTimestamp.toString(),
|
|
1048
|
+
EPICSHOP_PLAYGROUND_SRC_DIR: srcDir,
|
|
1049
|
+
EPICSHOP_PLAYGROUND_DEST_DIR: destDir,
|
|
1050
|
+
EPICSHOP_PLAYGROUND_WAS_RUNNING: playgroundWasRunning.toString(),
|
|
1051
|
+
EPICSHOP_PLAYGROUND_IS_STILL_RUNNING: playgroundIsStillRunning.toString(),
|
|
1052
|
+
EPICSHOP_PLAYGROUND_RESTART_PLAYGROUND: restartPlayground.toString(),
|
|
940
1053
|
},
|
|
941
1054
|
});
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
return files.map((f) => f.replace(dirPath, ''));
|
|
950
|
-
}
|
|
951
|
-
// Remove files from destDir that were in destDir before but are not in srcDir
|
|
952
|
-
const srcFiles = await getFiles(srcDir);
|
|
953
|
-
const destFiles = await getFiles(destDir);
|
|
954
|
-
const filesToDelete = destFiles.filter((fileName) => !srcFiles.includes(fileName));
|
|
955
|
-
for (const fileToDelete of filesToDelete) {
|
|
956
|
-
await fsExtra.remove(path.join(destDir, fileToDelete));
|
|
957
|
-
}
|
|
958
|
-
const appName = getAppName(srcDir);
|
|
959
|
-
await fsExtra.ensureDir(path.dirname(playgroundAppNameInfoPath));
|
|
960
|
-
await fsExtra.writeJSON(playgroundAppNameInfoPath, { appName });
|
|
961
|
-
const playgroundIsStillRunning = playgroundApp
|
|
962
|
-
? isAppRunning(playgroundApp)
|
|
963
|
-
: false;
|
|
964
|
-
const restartPlayground = playgroundWasRunning && !playgroundIsStillRunning;
|
|
965
|
-
// run postSet-playground script if it exists
|
|
966
|
-
const postSetPlaygroundPath = await firstToExist(path.join(srcDir, 'epicshop', 'post-set-playground.js'), path.join(workshopRoot, 'epicshop', 'post-set-playground.js'));
|
|
967
|
-
if (postSetPlaygroundPath) {
|
|
968
|
-
await execa('node', [postSetPlaygroundPath], {
|
|
969
|
-
cwd: workshopRoot,
|
|
970
|
-
stdio: 'inherit',
|
|
971
|
-
env: {
|
|
972
|
-
EPICSHOP_PLAYGROUND_TIMESTAMP: setPlaygroundTimestamp.toString(),
|
|
973
|
-
EPICSHOP_PLAYGROUND_SRC_DIR: srcDir,
|
|
974
|
-
EPICSHOP_PLAYGROUND_DEST_DIR: destDir,
|
|
975
|
-
EPICSHOP_PLAYGROUND_WAS_RUNNING: playgroundWasRunning.toString(),
|
|
976
|
-
EPICSHOP_PLAYGROUND_IS_STILL_RUNNING: playgroundIsStillRunning.toString(),
|
|
977
|
-
EPICSHOP_PLAYGROUND_RESTART_PLAYGROUND: restartPlayground.toString(),
|
|
978
|
-
},
|
|
979
|
-
});
|
|
980
|
-
}
|
|
981
|
-
// since we are running without the watcher we need to set the modified time
|
|
982
|
-
modifiedTimes.set(destDir, Date.now());
|
|
983
|
-
if (playgroundApp && restartPlayground) {
|
|
984
|
-
await runAppDev(playgroundApp);
|
|
985
|
-
await waitOnApp(playgroundApp);
|
|
986
|
-
}
|
|
987
|
-
});
|
|
988
|
-
// let the app know the playground changed
|
|
989
|
-
getWatcher()?.emit('all', 'playground', destDir);
|
|
1055
|
+
}
|
|
1056
|
+
// since we are running without the watcher we need to set the modified time
|
|
1057
|
+
modifiedTimes.set(destDir, Date.now());
|
|
1058
|
+
if (playgroundApp && restartPlayground) {
|
|
1059
|
+
await runAppDev(playgroundApp);
|
|
1060
|
+
await waitOnApp(playgroundApp);
|
|
1061
|
+
}
|
|
990
1062
|
}
|
|
991
1063
|
/**
|
|
992
1064
|
* The playground is based on another app. This returns the app the playground
|
|
@@ -1007,31 +1079,6 @@ export async function getPlaygroundAppName() {
|
|
|
1007
1079
|
return null;
|
|
1008
1080
|
}
|
|
1009
1081
|
}
|
|
1010
|
-
async function getDirModifiedTime(dir) {
|
|
1011
|
-
// we can't use modifiedTimes because it only stores the modified times of
|
|
1012
|
-
// things the app started.
|
|
1013
|
-
const isIgnored = await isGitIgnored({ cwd: dir });
|
|
1014
|
-
const files = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
1015
|
-
const modifiedTimes = await Promise.all(files.map(async (file) => {
|
|
1016
|
-
if (isIgnored(file.name))
|
|
1017
|
-
return 0;
|
|
1018
|
-
const filePath = path.join(dir, file.name);
|
|
1019
|
-
if (file.isDirectory()) {
|
|
1020
|
-
return getDirModifiedTime(filePath);
|
|
1021
|
-
}
|
|
1022
|
-
else {
|
|
1023
|
-
try {
|
|
1024
|
-
const { mtimeMs } = await fs.promises.stat(filePath);
|
|
1025
|
-
return mtimeMs;
|
|
1026
|
-
}
|
|
1027
|
-
catch {
|
|
1028
|
-
// Handle errors (e.g., file access permissions, file has been moved or deleted)
|
|
1029
|
-
return 0;
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
}));
|
|
1033
|
-
return Math.max(0, ...modifiedTimes); // Ensure there is a default of 0 if all files are ignored
|
|
1034
|
-
}
|
|
1035
1082
|
export function getAppDisplayName(a, allApps) {
|
|
1036
1083
|
let displayName = `${a.title} (${a.type})`;
|
|
1037
1084
|
if (isExerciseStepApp(a)) {
|
|
@@ -1081,4 +1128,30 @@ export function getRelativePath(filePath) {
|
|
|
1081
1128
|
.replace(playgroundPath, `playground${path.sep}`)
|
|
1082
1129
|
.replace(exercisesPath, '');
|
|
1083
1130
|
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Given a file path, this will determine the path to the app that file belongs to.
|
|
1133
|
+
*/
|
|
1134
|
+
export function getAppPathFromFilePath(filePath) {
|
|
1135
|
+
const [, withinWorkshopRootHalf] = filePath.split(workshopRoot);
|
|
1136
|
+
if (!withinWorkshopRootHalf) {
|
|
1137
|
+
return null;
|
|
1138
|
+
}
|
|
1139
|
+
const [part1, part2, part3] = withinWorkshopRootHalf
|
|
1140
|
+
.split(path.sep)
|
|
1141
|
+
.filter(Boolean);
|
|
1142
|
+
// Check if the file is in the playground
|
|
1143
|
+
if (part1 === 'playground') {
|
|
1144
|
+
return path.join(workshopRoot, 'playground');
|
|
1145
|
+
}
|
|
1146
|
+
// Check if the file is in an example
|
|
1147
|
+
if (part1 === 'examples' && part2) {
|
|
1148
|
+
return path.join(workshopRoot, 'examples', part2);
|
|
1149
|
+
}
|
|
1150
|
+
// Check if the file is in an exercise
|
|
1151
|
+
if (part1 === 'exercises' && part2 && part3) {
|
|
1152
|
+
return path.join(workshopRoot, 'exercises', part2, part3);
|
|
1153
|
+
}
|
|
1154
|
+
// If we couldn't determine the app path, return null
|
|
1155
|
+
return null;
|
|
1156
|
+
}
|
|
1084
1157
|
//# sourceMappingURL=apps.server.js.map
|