ignore output in include globs

This commit is contained in:
Gregor Lohaus
2026-05-24 14:57:44 +02:00
parent 0a512cdbc3
commit 0412cea241
3 changed files with 69 additions and 25 deletions

View File

@@ -314,40 +314,36 @@ function inferTemplatePath(outputPath: string, directoryMap: Map<string, string>
return joinPath(bestTemplateDir, suffix, basenamePath(normalized))
}
function walkFiles(root: string, current = root): string[] {
function walkFiles(root: string, excludedRoots: string[] = []): string[] {
const files: string[] = []
for (const entry of readdirSync(current).sort()) {
const path = resolvePath(current, entry)
const stat = statSync(path)
if (stat.isDirectory()) {
files.push(...walkFiles(root, path))
} else if (stat.isFile()) {
files.push(normalizePath(relative(root, path)))
const pending = [root]
while (pending.length > 0) {
const current = pending.pop()!
for (const entry of readdirSync(current).sort()) {
const path = resolvePath(current, entry)
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
}
function copyIncludedRenderedFiles(
renderedRoot: string,
templateRoot: string,
mapPath: string,
manifest: ReverseMapManifest,
include: ReverseOptions["include"],
includedOutputPaths: string[],
directoryMap: Map<string, string>,
): 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
for (const outputPath of walkFiles(renderedRoot)) {
if (outputPath === mapRelativePath) continue
if (mappedOutputPaths.has(outputPath)) continue
if (!matchesAny(outputPath, matchers)) continue
for (const outputPath of includedOutputPaths) {
const renderedPath = resolveInside(renderedRoot, outputPath)
const templatePath = resolveInside(templateRoot, inferTemplatePath(outputPath, directoryMap))
mkdirSync(dirname(templatePath), { recursive: true })
@@ -358,6 +354,25 @@ function copyIncludedRenderedFiles(
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(
renderedDir: string,
templateDir: string,
@@ -369,6 +384,14 @@ export function reverseDir(
? resolvePath(renderedRoot, options.mapPath)
: resolvePath(renderedRoot, ".tdir-map.json")
const manifest = readManifest(mapPath)
const directoryMap = buildDirectoryMap(manifest)
const includedOutputPaths = getIncludedRenderedFiles(
renderedRoot,
templateRoot,
mapPath,
manifest,
options.include,
)
const warnings: ReverseWarning[] = []
let filesWritten = 0
@@ -415,9 +438,8 @@ export function reverseDir(
filesWritten += copyIncludedRenderedFiles(
renderedRoot,
templateRoot,
mapPath,
manifest,
options.include,
includedOutputPaths,
directoryMap,
)
return { filesWritten, warnings }