@gregorlohaus/tdir 0.1.4 → 0.1.6
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 +23 -0
- package/dist/cli.js +153 -5
- package/dist/index.js +136 -0
- package/dist/reverse.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -208,8 +208,31 @@ tdir reverse ./output ./templates --map meta/reverse-map.json
|
|
|
208
208
|
bunx @gregorlohaus/tdir reverse ./output ./templates --map meta/reverse-map.json
|
|
209
209
|
```
|
|
210
210
|
|
|
211
|
+
New files created in the rendered directory are ignored by default. Include them explicitly with one or more glob patterns:
|
|
212
|
+
|
|
213
|
+
```sh
|
|
214
|
+
tdir reverse ./output ./templates --include "components/**"
|
|
215
|
+
tdir reverse ./output ./templates --include "components/**/*.ts" --include "pages/*.html"
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Programmatically, pass the same globs to `reverseDir`:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
reverseDir("./output", "./templates", {
|
|
222
|
+
include: ["components/**/*.ts", "pages/*.html"]
|
|
223
|
+
})
|
|
224
|
+
```
|
|
225
|
+
|
|
211
226
|
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.
|
|
212
227
|
|
|
228
|
+
The template output directory may be inside the rendered directory, for example:
|
|
229
|
+
|
|
230
|
+
```sh
|
|
231
|
+
tdir reverse ./ ./reversed --include "components/**"
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
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.
|
|
235
|
+
|
|
213
236
|
## Unmatched directives
|
|
214
237
|
|
|
215
238
|
A `<@if>` without a matching `<@endif>` throws when the renderer is initialized:
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
existsSync,
|
|
7
7
|
mkdirSync,
|
|
8
8
|
readFileSync,
|
|
9
|
+
readdirSync,
|
|
9
10
|
statSync,
|
|
10
11
|
writeFileSync
|
|
11
12
|
} from "node:fs";
|
|
@@ -39,6 +40,45 @@ function readManifest(mapPath) {
|
|
|
39
40
|
}
|
|
40
41
|
return manifest;
|
|
41
42
|
}
|
|
43
|
+
function normalizePath(path) {
|
|
44
|
+
return path.split("\\").join("/");
|
|
45
|
+
}
|
|
46
|
+
function escapeRegExp(text) {
|
|
47
|
+
return text.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
|
48
|
+
}
|
|
49
|
+
function globToRegExp(glob) {
|
|
50
|
+
let source = "^";
|
|
51
|
+
const pattern = normalizePath(glob);
|
|
52
|
+
for (let i = 0;i < pattern.length; i++) {
|
|
53
|
+
const char = pattern[i];
|
|
54
|
+
const next = pattern[i + 1];
|
|
55
|
+
if (char === "*" && next === "*") {
|
|
56
|
+
if (pattern[i + 2] === "/") {
|
|
57
|
+
source += "(?:.*/)?";
|
|
58
|
+
i += 2;
|
|
59
|
+
} else {
|
|
60
|
+
source += ".*";
|
|
61
|
+
i += 1;
|
|
62
|
+
}
|
|
63
|
+
} else if (char === "*") {
|
|
64
|
+
source += "[^/]*";
|
|
65
|
+
} else if (char === "?") {
|
|
66
|
+
source += "[^/]";
|
|
67
|
+
} else {
|
|
68
|
+
source += escapeRegExp(char);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return new RegExp(`${source}$`);
|
|
72
|
+
}
|
|
73
|
+
function getIncludeMatchers(include) {
|
|
74
|
+
if (!include)
|
|
75
|
+
return [];
|
|
76
|
+
return (Array.isArray(include) ? include : [include]).map(globToRegExp);
|
|
77
|
+
}
|
|
78
|
+
function matchesAny(path, matchers) {
|
|
79
|
+
const normalized = normalizePath(path);
|
|
80
|
+
return matchers.some((matcher) => matcher.test(normalized));
|
|
81
|
+
}
|
|
42
82
|
function replaceAtRange(content, token) {
|
|
43
83
|
if (!token.range)
|
|
44
84
|
return null;
|
|
@@ -159,11 +199,106 @@ function writeSkippedTemplate(templateRoot, skipped) {
|
|
|
159
199
|
writeFileSync(templatePath, content);
|
|
160
200
|
return 1;
|
|
161
201
|
}
|
|
202
|
+
function dirnamePath(path) {
|
|
203
|
+
const normalized = normalizePath(path);
|
|
204
|
+
const index = normalized.lastIndexOf("/");
|
|
205
|
+
return index === -1 ? "" : normalized.slice(0, index);
|
|
206
|
+
}
|
|
207
|
+
function basenamePath(path) {
|
|
208
|
+
const normalized = normalizePath(path);
|
|
209
|
+
const index = normalized.lastIndexOf("/");
|
|
210
|
+
return index === -1 ? normalized : normalized.slice(index + 1);
|
|
211
|
+
}
|
|
212
|
+
function joinPath(...parts) {
|
|
213
|
+
return parts.filter((part) => part !== "").join("/");
|
|
214
|
+
}
|
|
215
|
+
function buildDirectoryMap(manifest) {
|
|
216
|
+
const mappings = new Map([["", ""]]);
|
|
217
|
+
function addMapping(outputDir, templateDir) {
|
|
218
|
+
const outputParts = normalizePath(outputDir).split("/").filter(Boolean);
|
|
219
|
+
const templateParts = normalizePath(templateDir).split("/").filter(Boolean);
|
|
220
|
+
for (let i = 1;i <= outputParts.length; i++) {
|
|
221
|
+
if (i <= templateParts.length) {
|
|
222
|
+
mappings.set(outputParts.slice(0, i).join("/"), templateParts.slice(0, i).join("/"));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
mappings.set(normalizePath(outputDir), normalizePath(templateDir));
|
|
226
|
+
}
|
|
227
|
+
for (const file of manifest.files) {
|
|
228
|
+
const output = normalizePath(file.outputPath);
|
|
229
|
+
const template = normalizePath(file.templatePath);
|
|
230
|
+
addMapping(dirnamePath(output), dirnamePath(template));
|
|
231
|
+
if (file.tokens.some((token) => token.kind === "path"))
|
|
232
|
+
addMapping(output, template);
|
|
233
|
+
}
|
|
234
|
+
for (const skipped of manifest.skipped ?? []) {
|
|
235
|
+
if (skipped.kind === "directory")
|
|
236
|
+
continue;
|
|
237
|
+
addMapping(dirnamePath(skipped.templatePath), dirnamePath(skipped.templatePath));
|
|
238
|
+
}
|
|
239
|
+
return mappings;
|
|
240
|
+
}
|
|
241
|
+
function inferTemplatePath(outputPath, directoryMap) {
|
|
242
|
+
const normalized = normalizePath(outputPath);
|
|
243
|
+
const outputDir = dirnamePath(normalized);
|
|
244
|
+
let bestOutputDir = "";
|
|
245
|
+
let bestTemplateDir = "";
|
|
246
|
+
for (const [mappedOutputDir, mappedTemplateDir] of directoryMap) {
|
|
247
|
+
if (mappedOutputDir.length >= bestOutputDir.length && (outputDir === mappedOutputDir || outputDir.startsWith(`${mappedOutputDir}/`))) {
|
|
248
|
+
bestOutputDir = mappedOutputDir;
|
|
249
|
+
bestTemplateDir = mappedTemplateDir;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const suffix = bestOutputDir === "" ? outputDir : outputDir.slice(bestOutputDir.length).replace(/^\//, "");
|
|
253
|
+
return joinPath(bestTemplateDir, suffix, basenamePath(normalized));
|
|
254
|
+
}
|
|
255
|
+
function walkFiles(root, excludedRoots = []) {
|
|
256
|
+
const files = [];
|
|
257
|
+
const pending = [root];
|
|
258
|
+
while (pending.length > 0) {
|
|
259
|
+
const current = pending.pop();
|
|
260
|
+
for (const entry of readdirSync(current).sort()) {
|
|
261
|
+
const path = resolvePath(current, entry);
|
|
262
|
+
if (excludedRoots.some((excluded) => isInsidePath(excluded, path)))
|
|
263
|
+
continue;
|
|
264
|
+
const stat = statSync(path);
|
|
265
|
+
if (stat.isDirectory()) {
|
|
266
|
+
pending.push(path);
|
|
267
|
+
} else if (stat.isFile()) {
|
|
268
|
+
files.push(normalizePath(relative(root, path)));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return files;
|
|
273
|
+
}
|
|
274
|
+
function copyIncludedRenderedFiles(renderedRoot, templateRoot, includedOutputPaths, directoryMap) {
|
|
275
|
+
let filesWritten = 0;
|
|
276
|
+
for (const outputPath of includedOutputPaths) {
|
|
277
|
+
const renderedPath = resolveInside(renderedRoot, outputPath);
|
|
278
|
+
const templatePath = resolveInside(templateRoot, inferTemplatePath(outputPath, directoryMap));
|
|
279
|
+
mkdirSync(dirname(templatePath), { recursive: true });
|
|
280
|
+
copyFileSync(renderedPath, templatePath);
|
|
281
|
+
filesWritten += 1;
|
|
282
|
+
}
|
|
283
|
+
return filesWritten;
|
|
284
|
+
}
|
|
285
|
+
function getIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest, include) {
|
|
286
|
+
const matchers = getIncludeMatchers(include);
|
|
287
|
+
if (matchers.length === 0)
|
|
288
|
+
return [];
|
|
289
|
+
const mappedOutputPaths = new Set(manifest.files.map((file) => normalizePath(file.outputPath)));
|
|
290
|
+
const mapRelativePath = normalizePath(relative(renderedRoot, mapPath));
|
|
291
|
+
return walkFiles(renderedRoot, [templateRoot]).filter((outputPath) => {
|
|
292
|
+
return outputPath !== mapRelativePath && !mappedOutputPaths.has(outputPath) && matchesAny(outputPath, matchers);
|
|
293
|
+
});
|
|
294
|
+
}
|
|
162
295
|
function reverseDir(renderedDir, templateDir, options = {}) {
|
|
163
296
|
const renderedRoot = resolvePath(renderedDir);
|
|
164
297
|
const templateRoot = resolvePath(templateDir);
|
|
165
298
|
const mapPath = options.mapPath ? resolvePath(renderedRoot, options.mapPath) : resolvePath(renderedRoot, ".tdir-map.json");
|
|
166
299
|
const manifest = readManifest(mapPath);
|
|
300
|
+
const directoryMap = buildDirectoryMap(manifest);
|
|
301
|
+
const includedOutputPaths = getIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest, options.include);
|
|
167
302
|
const warnings = [];
|
|
168
303
|
let filesWritten = 0;
|
|
169
304
|
for (const file of manifest.files) {
|
|
@@ -198,6 +333,7 @@ function reverseDir(renderedDir, templateDir, options = {}) {
|
|
|
198
333
|
for (const skipped of manifest.skipped ?? []) {
|
|
199
334
|
filesWritten += writeSkippedTemplate(templateRoot, skipped);
|
|
200
335
|
}
|
|
336
|
+
filesWritten += copyIncludedRenderedFiles(renderedRoot, templateRoot, includedOutputPaths, directoryMap);
|
|
201
337
|
return { filesWritten, warnings };
|
|
202
338
|
}
|
|
203
339
|
|
|
@@ -206,7 +342,7 @@ function printHelp() {
|
|
|
206
342
|
console.log(`tdir
|
|
207
343
|
|
|
208
344
|
Usage:
|
|
209
|
-
tdir reverse <rendered-dir> <template-dir> [--map <path>]
|
|
345
|
+
tdir reverse <rendered-dir> <template-dir> [--map <path>] [--include <glob>...]
|
|
210
346
|
|
|
211
347
|
Commands:
|
|
212
348
|
reverse Rebuild template files from a rendered directory and reverse map
|
|
@@ -214,16 +350,18 @@ Commands:
|
|
|
214
350
|
Options:
|
|
215
351
|
--map Reverse map path. Defaults to <rendered-dir>/.tdir-map.json.
|
|
216
352
|
Relative paths are resolved from <rendered-dir>.
|
|
353
|
+
--include Include new rendered files matching a glob. Can be repeated.
|
|
217
354
|
--help Show this help message.
|
|
218
355
|
`);
|
|
219
356
|
}
|
|
220
357
|
function parseReverseArgs(args) {
|
|
221
358
|
const positional = [];
|
|
359
|
+
const include = [];
|
|
222
360
|
let mapPath;
|
|
223
361
|
for (let i = 0;i < args.length; i++) {
|
|
224
362
|
const arg = args[i];
|
|
225
363
|
if (arg === "--help" || arg === "-h") {
|
|
226
|
-
return { help: true, positional, mapPath };
|
|
364
|
+
return { help: true, positional, mapPath, include };
|
|
227
365
|
}
|
|
228
366
|
if (arg === "--map") {
|
|
229
367
|
const value = args[++i];
|
|
@@ -232,9 +370,16 @@ function parseReverseArgs(args) {
|
|
|
232
370
|
mapPath = value;
|
|
233
371
|
continue;
|
|
234
372
|
}
|
|
373
|
+
if (arg === "--include") {
|
|
374
|
+
const value = args[++i];
|
|
375
|
+
if (!value)
|
|
376
|
+
throw new Error("Missing value for --include");
|
|
377
|
+
include.push(value);
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
235
380
|
positional.push(arg);
|
|
236
381
|
}
|
|
237
|
-
return { help: false, positional, mapPath };
|
|
382
|
+
return { help: false, positional, mapPath, include };
|
|
238
383
|
}
|
|
239
384
|
function main(argv) {
|
|
240
385
|
const [command, ...args] = argv;
|
|
@@ -252,9 +397,12 @@ function main(argv) {
|
|
|
252
397
|
}
|
|
253
398
|
const [renderedDir, templateDir] = parsed.positional;
|
|
254
399
|
if (!renderedDir || !templateDir || parsed.positional.length > 2) {
|
|
255
|
-
throw new Error("Usage: tdir reverse <rendered-dir> <template-dir> [--map <path>]");
|
|
400
|
+
throw new Error("Usage: tdir reverse <rendered-dir> <template-dir> [--map <path>] [--include <glob>...]");
|
|
256
401
|
}
|
|
257
|
-
const result = reverseDir(renderedDir, templateDir, {
|
|
402
|
+
const result = reverseDir(renderedDir, templateDir, {
|
|
403
|
+
mapPath: parsed.mapPath,
|
|
404
|
+
include: parsed.include
|
|
405
|
+
});
|
|
258
406
|
console.log(`Wrote ${result.filesWritten} file${result.filesWritten === 1 ? "" : "s"}`);
|
|
259
407
|
for (const warning of result.warnings) {
|
|
260
408
|
console.warn(`Warning: ${warning.outputPath}: ${warning.message}`);
|
package/dist/index.js
CHANGED
|
@@ -492,6 +492,7 @@ import {
|
|
|
492
492
|
existsSync,
|
|
493
493
|
mkdirSync as mkdirSync2,
|
|
494
494
|
readFileSync as readFileSync3,
|
|
495
|
+
readdirSync as readdirSync3,
|
|
495
496
|
statSync as statSync3,
|
|
496
497
|
writeFileSync as writeFileSync2
|
|
497
498
|
} from "node:fs";
|
|
@@ -525,6 +526,45 @@ function readManifest(mapPath) {
|
|
|
525
526
|
}
|
|
526
527
|
return manifest;
|
|
527
528
|
}
|
|
529
|
+
function normalizePath(path) {
|
|
530
|
+
return path.split("\\").join("/");
|
|
531
|
+
}
|
|
532
|
+
function escapeRegExp(text) {
|
|
533
|
+
return text.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
|
534
|
+
}
|
|
535
|
+
function globToRegExp(glob) {
|
|
536
|
+
let source = "^";
|
|
537
|
+
const pattern = normalizePath(glob);
|
|
538
|
+
for (let i = 0;i < pattern.length; i++) {
|
|
539
|
+
const char = pattern[i];
|
|
540
|
+
const next = pattern[i + 1];
|
|
541
|
+
if (char === "*" && next === "*") {
|
|
542
|
+
if (pattern[i + 2] === "/") {
|
|
543
|
+
source += "(?:.*/)?";
|
|
544
|
+
i += 2;
|
|
545
|
+
} else {
|
|
546
|
+
source += ".*";
|
|
547
|
+
i += 1;
|
|
548
|
+
}
|
|
549
|
+
} else if (char === "*") {
|
|
550
|
+
source += "[^/]*";
|
|
551
|
+
} else if (char === "?") {
|
|
552
|
+
source += "[^/]";
|
|
553
|
+
} else {
|
|
554
|
+
source += escapeRegExp(char);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return new RegExp(`${source}$`);
|
|
558
|
+
}
|
|
559
|
+
function getIncludeMatchers(include) {
|
|
560
|
+
if (!include)
|
|
561
|
+
return [];
|
|
562
|
+
return (Array.isArray(include) ? include : [include]).map(globToRegExp);
|
|
563
|
+
}
|
|
564
|
+
function matchesAny(path, matchers) {
|
|
565
|
+
const normalized = normalizePath(path);
|
|
566
|
+
return matchers.some((matcher) => matcher.test(normalized));
|
|
567
|
+
}
|
|
528
568
|
function replaceAtRange(content, token) {
|
|
529
569
|
if (!token.range)
|
|
530
570
|
return null;
|
|
@@ -645,11 +685,106 @@ function writeSkippedTemplate(templateRoot, skipped) {
|
|
|
645
685
|
writeFileSync2(templatePath, content);
|
|
646
686
|
return 1;
|
|
647
687
|
}
|
|
688
|
+
function dirnamePath(path) {
|
|
689
|
+
const normalized = normalizePath(path);
|
|
690
|
+
const index = normalized.lastIndexOf("/");
|
|
691
|
+
return index === -1 ? "" : normalized.slice(0, index);
|
|
692
|
+
}
|
|
693
|
+
function basenamePath(path) {
|
|
694
|
+
const normalized = normalizePath(path);
|
|
695
|
+
const index = normalized.lastIndexOf("/");
|
|
696
|
+
return index === -1 ? normalized : normalized.slice(index + 1);
|
|
697
|
+
}
|
|
698
|
+
function joinPath(...parts) {
|
|
699
|
+
return parts.filter((part) => part !== "").join("/");
|
|
700
|
+
}
|
|
701
|
+
function buildDirectoryMap(manifest) {
|
|
702
|
+
const mappings = new Map([["", ""]]);
|
|
703
|
+
function addMapping(outputDir, templateDir) {
|
|
704
|
+
const outputParts = normalizePath(outputDir).split("/").filter(Boolean);
|
|
705
|
+
const templateParts = normalizePath(templateDir).split("/").filter(Boolean);
|
|
706
|
+
for (let i = 1;i <= outputParts.length; i++) {
|
|
707
|
+
if (i <= templateParts.length) {
|
|
708
|
+
mappings.set(outputParts.slice(0, i).join("/"), templateParts.slice(0, i).join("/"));
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
mappings.set(normalizePath(outputDir), normalizePath(templateDir));
|
|
712
|
+
}
|
|
713
|
+
for (const file of manifest.files) {
|
|
714
|
+
const output = normalizePath(file.outputPath);
|
|
715
|
+
const template = normalizePath(file.templatePath);
|
|
716
|
+
addMapping(dirnamePath(output), dirnamePath(template));
|
|
717
|
+
if (file.tokens.some((token) => token.kind === "path"))
|
|
718
|
+
addMapping(output, template);
|
|
719
|
+
}
|
|
720
|
+
for (const skipped of manifest.skipped ?? []) {
|
|
721
|
+
if (skipped.kind === "directory")
|
|
722
|
+
continue;
|
|
723
|
+
addMapping(dirnamePath(skipped.templatePath), dirnamePath(skipped.templatePath));
|
|
724
|
+
}
|
|
725
|
+
return mappings;
|
|
726
|
+
}
|
|
727
|
+
function inferTemplatePath(outputPath, directoryMap) {
|
|
728
|
+
const normalized = normalizePath(outputPath);
|
|
729
|
+
const outputDir = dirnamePath(normalized);
|
|
730
|
+
let bestOutputDir = "";
|
|
731
|
+
let bestTemplateDir = "";
|
|
732
|
+
for (const [mappedOutputDir, mappedTemplateDir] of directoryMap) {
|
|
733
|
+
if (mappedOutputDir.length >= bestOutputDir.length && (outputDir === mappedOutputDir || outputDir.startsWith(`${mappedOutputDir}/`))) {
|
|
734
|
+
bestOutputDir = mappedOutputDir;
|
|
735
|
+
bestTemplateDir = mappedTemplateDir;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
const suffix = bestOutputDir === "" ? outputDir : outputDir.slice(bestOutputDir.length).replace(/^\//, "");
|
|
739
|
+
return joinPath(bestTemplateDir, suffix, basenamePath(normalized));
|
|
740
|
+
}
|
|
741
|
+
function walkFiles(root, excludedRoots = []) {
|
|
742
|
+
const files = [];
|
|
743
|
+
const pending = [root];
|
|
744
|
+
while (pending.length > 0) {
|
|
745
|
+
const current = pending.pop();
|
|
746
|
+
for (const entry of readdirSync3(current).sort()) {
|
|
747
|
+
const path = resolvePath2(current, entry);
|
|
748
|
+
if (excludedRoots.some((excluded) => isInsidePath2(excluded, path)))
|
|
749
|
+
continue;
|
|
750
|
+
const stat = statSync3(path);
|
|
751
|
+
if (stat.isDirectory()) {
|
|
752
|
+
pending.push(path);
|
|
753
|
+
} else if (stat.isFile()) {
|
|
754
|
+
files.push(normalizePath(relative2(root, path)));
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
return files;
|
|
759
|
+
}
|
|
760
|
+
function copyIncludedRenderedFiles(renderedRoot, templateRoot, includedOutputPaths, directoryMap) {
|
|
761
|
+
let filesWritten = 0;
|
|
762
|
+
for (const outputPath of includedOutputPaths) {
|
|
763
|
+
const renderedPath = resolveInside(renderedRoot, outputPath);
|
|
764
|
+
const templatePath = resolveInside(templateRoot, inferTemplatePath(outputPath, directoryMap));
|
|
765
|
+
mkdirSync2(dirname2(templatePath), { recursive: true });
|
|
766
|
+
copyFileSync2(renderedPath, templatePath);
|
|
767
|
+
filesWritten += 1;
|
|
768
|
+
}
|
|
769
|
+
return filesWritten;
|
|
770
|
+
}
|
|
771
|
+
function getIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest, include) {
|
|
772
|
+
const matchers = getIncludeMatchers(include);
|
|
773
|
+
if (matchers.length === 0)
|
|
774
|
+
return [];
|
|
775
|
+
const mappedOutputPaths = new Set(manifest.files.map((file) => normalizePath(file.outputPath)));
|
|
776
|
+
const mapRelativePath = normalizePath(relative2(renderedRoot, mapPath));
|
|
777
|
+
return walkFiles(renderedRoot, [templateRoot]).filter((outputPath) => {
|
|
778
|
+
return outputPath !== mapRelativePath && !mappedOutputPaths.has(outputPath) && matchesAny(outputPath, matchers);
|
|
779
|
+
});
|
|
780
|
+
}
|
|
648
781
|
function reverseDir(renderedDir, templateDir, options = {}) {
|
|
649
782
|
const renderedRoot = resolvePath2(renderedDir);
|
|
650
783
|
const templateRoot = resolvePath2(templateDir);
|
|
651
784
|
const mapPath = options.mapPath ? resolvePath2(renderedRoot, options.mapPath) : resolvePath2(renderedRoot, ".tdir-map.json");
|
|
652
785
|
const manifest = readManifest(mapPath);
|
|
786
|
+
const directoryMap = buildDirectoryMap(manifest);
|
|
787
|
+
const includedOutputPaths = getIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest, options.include);
|
|
653
788
|
const warnings = [];
|
|
654
789
|
let filesWritten = 0;
|
|
655
790
|
for (const file of manifest.files) {
|
|
@@ -684,6 +819,7 @@ function reverseDir(renderedDir, templateDir, options = {}) {
|
|
|
684
819
|
for (const skipped of manifest.skipped ?? []) {
|
|
685
820
|
filesWritten += writeSkippedTemplate(templateRoot, skipped);
|
|
686
821
|
}
|
|
822
|
+
filesWritten += copyIncludedRenderedFiles(renderedRoot, templateRoot, includedOutputPaths, directoryMap);
|
|
687
823
|
return { filesWritten, warnings };
|
|
688
824
|
}
|
|
689
825
|
|
package/dist/reverse.d.ts
CHANGED