Skip to content

Commit 29920da

Browse files
committed
Recursively copy theme/keep paths in theme after refresh
This promotes theme/keep to be a customization technique. Nested paths could be kept in theme/keep and writ could be always running with refresh-theme option. This enables theme development inside keep folder, while everything else respects the latest updates from writ. In other words, extract theme/keep contents recursively, once the theme refreshing is complete. So, keep is now not only keeping things from being deleted, it delivers things to given paths after refresh.
1 parent 895f4f6 commit 29920da

File tree

2 files changed

+190
-21
lines changed

2 files changed

+190
-21
lines changed

src/e2e-tests/theme.test.js

Lines changed: 166 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -317,33 +317,178 @@ test('Theme', t => {
317317
}
318318
})
319319

320-
/*
321-
t.test('refreshTheme option when there is no theme/keep', async t => {
322-
const dir = await createTempDir(t)
320+
t.test('theme/keep will recursively override custom theme paths', async t => {
321+
t.plan(3)
323322

324-
await writ.build({
325-
rootDirectory: dir.name
326-
})
323+
const testDir = join(tmpdir(), 'theme-keep-override')
324+
const rootDirectory = testDir
325+
const themeDirectory = 'theme'
327326

328-
const { themeDirectory } = writ.getDefaultSettings()
327+
try {
328+
await mkdir(testDir, { recursive: true })
329329

330-
const deletedFileName = 'deleted.css'
331-
await dir.mkFile(join(themeDirectory, deletedFileName), '')
330+
await writ.build({
331+
rootDirectory: testDir
332+
})
332333

333-
await writ.build({
334-
rootDirectory: dir.name,
335-
refreshTheme: true
336-
})
334+
const themePath = join(testDir, themeDirectory)
335+
const keepPath = join(themePath, 'keep')
336+
const assetsPath = join(themePath, 'assets')
337337

338-
await common.builds(t, dir.name, {
339-
themeDirectoryPaths: {
340-
notExists: [deletedFileName]
341-
}
342-
})
338+
// Count files in assets before override
339+
const assetsContentsBefore = await readdir(
340+
assetsPath,
341+
{ recursive: true, withFileTypes: true }
342+
)
343+
const fileCountBefore = assetsContentsBefore.filter(
344+
e => !e.isDirectory()
345+
).length
346+
347+
// Create one customized file in keep
348+
await mkdir(join(keepPath, 'assets'), { recursive: true })
349+
await writeFile(
350+
join(keepPath, 'assets', 'custom.css'),
351+
'customized styles'
352+
)
353+
354+
await writ.build({
355+
rootDirectory: testDir,
356+
refreshTheme: true
357+
})
358+
359+
const assetsContentsAfter = await readdir(
360+
assetsPath,
361+
{ recursive: true, withFileTypes: true }
362+
)
363+
const fileCountAfter = assetsContentsAfter.filter(
364+
e => !e.isDirectory()
365+
).length
366+
367+
const customCssContent = await readFile(
368+
join(assetsPath, 'custom.css'),
369+
'utf-8'
370+
)
371+
372+
t.equal(
373+
customCssContent,
374+
'customized styles',
375+
'custom file from keep is applied'
376+
)
377+
378+
t.ok(
379+
fileCountAfter > 1,
380+
'assets folder contains multiple files'
381+
)
382+
383+
t.equal(
384+
fileCountAfter,
385+
fileCountBefore + 1,
386+
'assets folder has original files plus the new one (not replaced)'
387+
)
388+
} finally {
389+
await rm(testDir, { recursive: true, force: true })
390+
}
391+
})
392+
393+
t.test('theme/keep respects deep nesting without replacing parent folders', async t => {
394+
t.plan(2)
395+
396+
const testDir = join(tmpdir(), 'theme-keep-deep-nesting')
397+
const rootDirectory = testDir
398+
const themeDirectory = 'theme'
399+
400+
try {
401+
await mkdir(testDir, { recursive: true })
402+
403+
await writ.build({
404+
rootDirectory: testDir
405+
})
406+
407+
const themePath = join(testDir, themeDirectory)
408+
const keepPath = join(themePath, 'keep')
409+
410+
// Create deeply nested file in keep
411+
const deepPath = join(keepPath, 'deep', 'nested', 'folder', 'structure')
412+
await mkdir(deepPath, { recursive: true })
413+
await writeFile(
414+
join(deepPath, 'custom.txt'),
415+
'deeply nested content'
416+
)
417+
418+
await writ.build({
419+
rootDirectory: testDir,
420+
refreshTheme: true
421+
})
422+
423+
const deepThemePath = join(
424+
themePath,
425+
'deep',
426+
'nested',
427+
'folder',
428+
'structure'
429+
)
430+
const deepContent = await readFile(
431+
join(deepThemePath, 'custom.txt'),
432+
'utf-8'
433+
)
434+
435+
t.equal(
436+
deepContent,
437+
'deeply nested content',
438+
'deeply nested file from keep is applied'
439+
)
440+
441+
const deepFolderContents = await readdir(deepThemePath)
442+
t.equal(
443+
deepFolderContents.length,
444+
1,
445+
'deep folder only contains the custom file (no existing files to preserve)'
446+
)
447+
} finally {
448+
await rm(testDir, { recursive: true, force: true })
449+
}
450+
})
451+
452+
t.test('when keep has a file where theme has a directory with the same name', async t => {
453+
t.plan(1)
454+
455+
const testDir = join(tmpdir(), 'theme-keep-file-dir-collision')
456+
const rootDirectory = testDir
457+
const themeDirectory = 'theme'
458+
459+
try {
460+
await mkdir(testDir, { recursive: true })
461+
462+
await writ.build({
463+
rootDirectory: testDir
464+
})
465+
466+
const themePath = join(testDir, themeDirectory)
467+
const keepPath = join(themePath, 'keep')
468+
469+
// Create a file in keep where theme likely has a directory
470+
// (assets exists in theme and has subdirectories)
471+
await mkdir(keepPath, { recursive: true })
472+
await writeFile(
473+
join(keepPath, 'assets'),
474+
'file content'
475+
)
343476

344-
const themeDirectoryContents = await readdir(join(dir.name, themeDirectory))
345-
hasNotPaths(t, themeDirectoryContents, [deletedFileName], 'theme directory is refreshed')
477+
try {
478+
await writ.build({
479+
rootDirectory: testDir,
480+
refreshTheme: true
481+
})
482+
t.fail('should have thrown an error when file collides with directory')
483+
} catch (e) {
484+
t.ok(
485+
e,
486+
'error is thrown when file in keep tries to overwrite directory in theme'
487+
)
488+
}
489+
} finally {
490+
await rm(testDir, { recursive: true, force: true })
491+
}
346492
})
347-
*/
348493

349494
})

src/theme/index.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,37 @@ const Methods = (() => {
6060
}
6161
}
6262

63+
const applyKeepOverrides = async (keepBackupPath, themePath) => {
64+
const entries = await readdir(keepBackupPath, {
65+
recursive: true,
66+
withFileTypes: true
67+
})
68+
69+
await Promise.all(
70+
entries
71+
.filter(entry => !entry.isDirectory())
72+
.map(entry => {
73+
const relativePath = join(
74+
entry.parentPath.replace(keepBackupPath, ''),
75+
entry.name
76+
)
77+
return cp(
78+
join(keepBackupPath, relativePath),
79+
join(themePath, relativePath)
80+
)
81+
})
82+
)
83+
}
84+
6385
const refreshThemeDir = async (themePath, keepBackupPath, keepPath) => {
6486
try {
6587
Debug.debugLog('rm -r', themePath)
6688
await rm(themePath, { recursive: true })
6789
await makeCustomThemeDirectory(themePath)
6890
if (keepBackupPath) {
6991
await cp(keepBackupPath, keepPath, { recursive: true })
92+
// Apply keep directory customizations, file by file
93+
await applyKeepOverrides(keepBackupPath, themePath)
7094
}
7195
} catch (e) {
7296
console.log(`Failed refreshing ${customThemePath}`)

0 commit comments

Comments
 (0)