Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d01b2f7c9 | ||
|
|
0412cea241 |
@@ -225,6 +225,14 @@ reverseDir("./output", "./templates", {
|
|||||||
|
|
||||||
The command writes files at their original template paths, restores recorded `<@var(...)>` tokens, wraps edited inline conditional output back in the original conditional block, and restores template files that were skipped by path conditionals.
|
The command writes files at their original template paths, restores recorded `<@var(...)>` tokens, wraps edited inline conditional output back in the original conditional block, and restores template files that were skipped by path conditionals.
|
||||||
|
|
||||||
|
The template output directory may be inside the rendered directory, for example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
tdir reverse ./ ./reversed --include "components/**"
|
||||||
|
```
|
||||||
|
|
||||||
|
When the template output directory is inside the rendered directory, reverse snapshots included files before writing and excludes the output directory from include glob matching.
|
||||||
|
|
||||||
## Unmatched directives
|
## Unmatched directives
|
||||||
|
|
||||||
A `<@if>` without a matching `<@endif>` throws when the renderer is initialized:
|
A `<@if>` without a matching `<@endif>` throws when the renderer is initialized:
|
||||||
|
|||||||
@@ -245,6 +245,20 @@ test("reverseDir only includes new rendered files matching include globs", () =>
|
|||||||
expect(existsSync(join(templateOut, "<@if(context.web.create)><@var(context.web.dir)>", "debug.tmp"))).toBe(false)
|
expect(existsSync(join(templateOut, "<@if(context.web.create)><@var(context.web.dir)>", "debug.tmp"))).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("reverseDir can write templates inside rendered output without including its own writes", () => {
|
||||||
|
const createRenderer = initRenderer("./testdata/if_example")
|
||||||
|
const render = createRenderer(ifExampleSchema)
|
||||||
|
const renderedOut = join(tmp, "rendered")
|
||||||
|
render(renderedOut, { web: true, header: { render: true, text: "My Title" } }, { reverseMap: true })
|
||||||
|
writeFileSync(join(renderedOut, "new.html"), "<main>new</main>\n")
|
||||||
|
|
||||||
|
const result = reverseDir(renderedOut, join(renderedOut, "reversed"), { include: ["**/*"] })
|
||||||
|
expect(result.warnings).toEqual([])
|
||||||
|
expect(existsSync(join(renderedOut, "reversed", "<@if(context.web)>web", "if_example.html"))).toBe(true)
|
||||||
|
expect(existsSync(join(renderedOut, "reversed", "new.html"))).toBe(true)
|
||||||
|
expect(existsSync(join(renderedOut, "reversed", "reversed", "new.html"))).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
test("wrong schema throws error",() => {
|
test("wrong schema throws error",() => {
|
||||||
const createRenderer = initRenderer("./testdata/if_example")
|
const createRenderer = initRenderer("./testdata/if_example")
|
||||||
expect(() => createRenderer(z.object({
|
expect(() => createRenderer(z.object({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@gregorlohaus/tdir",
|
"name": "@gregorlohaus/tdir",
|
||||||
"version": "0.1.5",
|
"version": "0.1.6",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
|
|||||||
72
reverse.ts
72
reverse.ts
@@ -314,40 +314,36 @@ function inferTemplatePath(outputPath: string, directoryMap: Map<string, string>
|
|||||||
return joinPath(bestTemplateDir, suffix, basenamePath(normalized))
|
return joinPath(bestTemplateDir, suffix, basenamePath(normalized))
|
||||||
}
|
}
|
||||||
|
|
||||||
function walkFiles(root: string, current = root): string[] {
|
function walkFiles(root: string, excludedRoots: string[] = []): string[] {
|
||||||
const files: string[] = []
|
const files: string[] = []
|
||||||
for (const entry of readdirSync(current).sort()) {
|
const pending = [root]
|
||||||
const path = resolvePath(current, entry)
|
|
||||||
const stat = statSync(path)
|
while (pending.length > 0) {
|
||||||
if (stat.isDirectory()) {
|
const current = pending.pop()!
|
||||||
files.push(...walkFiles(root, path))
|
for (const entry of readdirSync(current).sort()) {
|
||||||
} else if (stat.isFile()) {
|
const path = resolvePath(current, entry)
|
||||||
files.push(normalizePath(relative(root, path)))
|
if (excludedRoots.some(excluded => isInsidePath(excluded, path))) continue
|
||||||
|
const stat = statSync(path)
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
pending.push(path)
|
||||||
|
} else if (stat.isFile()) {
|
||||||
|
files.push(normalizePath(relative(root, path)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyIncludedRenderedFiles(
|
function copyIncludedRenderedFiles(
|
||||||
renderedRoot: string,
|
renderedRoot: string,
|
||||||
templateRoot: string,
|
templateRoot: string,
|
||||||
mapPath: string,
|
includedOutputPaths: string[],
|
||||||
manifest: ReverseMapManifest,
|
directoryMap: Map<string, string>,
|
||||||
include: ReverseOptions["include"],
|
|
||||||
): number {
|
): number {
|
||||||
const matchers = getIncludeMatchers(include)
|
|
||||||
if (matchers.length === 0) return 0
|
|
||||||
|
|
||||||
const mappedOutputPaths = new Set(manifest.files.map(file => normalizePath(file.outputPath)))
|
|
||||||
const mapRelativePath = normalizePath(relative(renderedRoot, mapPath))
|
|
||||||
const directoryMap = buildDirectoryMap(manifest)
|
|
||||||
let filesWritten = 0
|
let filesWritten = 0
|
||||||
|
|
||||||
for (const outputPath of walkFiles(renderedRoot)) {
|
for (const outputPath of includedOutputPaths) {
|
||||||
if (outputPath === mapRelativePath) continue
|
|
||||||
if (mappedOutputPaths.has(outputPath)) continue
|
|
||||||
if (!matchesAny(outputPath, matchers)) continue
|
|
||||||
|
|
||||||
const renderedPath = resolveInside(renderedRoot, outputPath)
|
const renderedPath = resolveInside(renderedRoot, outputPath)
|
||||||
const templatePath = resolveInside(templateRoot, inferTemplatePath(outputPath, directoryMap))
|
const templatePath = resolveInside(templateRoot, inferTemplatePath(outputPath, directoryMap))
|
||||||
mkdirSync(dirname(templatePath), { recursive: true })
|
mkdirSync(dirname(templatePath), { recursive: true })
|
||||||
@@ -358,6 +354,25 @@ function copyIncludedRenderedFiles(
|
|||||||
return filesWritten
|
return filesWritten
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getIncludedRenderedFiles(
|
||||||
|
renderedRoot: string,
|
||||||
|
templateRoot: string,
|
||||||
|
mapPath: string,
|
||||||
|
manifest: ReverseMapManifest,
|
||||||
|
include: ReverseOptions["include"],
|
||||||
|
): string[] {
|
||||||
|
const matchers = getIncludeMatchers(include)
|
||||||
|
if (matchers.length === 0) return []
|
||||||
|
|
||||||
|
const mappedOutputPaths = new Set(manifest.files.map(file => normalizePath(file.outputPath)))
|
||||||
|
const mapRelativePath = normalizePath(relative(renderedRoot, mapPath))
|
||||||
|
return walkFiles(renderedRoot, [templateRoot]).filter(outputPath => {
|
||||||
|
return outputPath !== mapRelativePath
|
||||||
|
&& !mappedOutputPaths.has(outputPath)
|
||||||
|
&& matchesAny(outputPath, matchers)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function reverseDir(
|
export function reverseDir(
|
||||||
renderedDir: string,
|
renderedDir: string,
|
||||||
templateDir: string,
|
templateDir: string,
|
||||||
@@ -369,6 +384,14 @@ export function reverseDir(
|
|||||||
? resolvePath(renderedRoot, options.mapPath)
|
? resolvePath(renderedRoot, options.mapPath)
|
||||||
: resolvePath(renderedRoot, ".tdir-map.json")
|
: resolvePath(renderedRoot, ".tdir-map.json")
|
||||||
const manifest = readManifest(mapPath)
|
const manifest = readManifest(mapPath)
|
||||||
|
const directoryMap = buildDirectoryMap(manifest)
|
||||||
|
const includedOutputPaths = getIncludedRenderedFiles(
|
||||||
|
renderedRoot,
|
||||||
|
templateRoot,
|
||||||
|
mapPath,
|
||||||
|
manifest,
|
||||||
|
options.include,
|
||||||
|
)
|
||||||
const warnings: ReverseWarning[] = []
|
const warnings: ReverseWarning[] = []
|
||||||
let filesWritten = 0
|
let filesWritten = 0
|
||||||
|
|
||||||
@@ -415,9 +438,8 @@ export function reverseDir(
|
|||||||
filesWritten += copyIncludedRenderedFiles(
|
filesWritten += copyIncludedRenderedFiles(
|
||||||
renderedRoot,
|
renderedRoot,
|
||||||
templateRoot,
|
templateRoot,
|
||||||
mapPath,
|
includedOutputPaths,
|
||||||
manifest,
|
directoryMap,
|
||||||
options.include,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return { filesWritten, warnings }
|
return { filesWritten, warnings }
|
||||||
|
|||||||
Reference in New Issue
Block a user