@gregorlohaus/tdir 0.1.5 → 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 CHANGED
@@ -225,6 +225,14 @@ reverseDir("./output", "./templates", {
225
225
 
226
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.
227
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
+
228
236
  ## Unmatched directives
229
237
 
230
238
  A `<@if>` without a matching `<@endif>` throws when the renderer is initialized:
package/dist/cli.js CHANGED
@@ -252,34 +252,28 @@ function inferTemplatePath(outputPath, directoryMap) {
252
252
  const suffix = bestOutputDir === "" ? outputDir : outputDir.slice(bestOutputDir.length).replace(/^\//, "");
253
253
  return joinPath(bestTemplateDir, suffix, basenamePath(normalized));
254
254
  }
255
- function walkFiles(root, current = root) {
255
+ function walkFiles(root, excludedRoots = []) {
256
256
  const files = [];
257
- for (const entry of readdirSync(current).sort()) {
258
- const path = resolvePath(current, entry);
259
- const stat = statSync(path);
260
- if (stat.isDirectory()) {
261
- files.push(...walkFiles(root, path));
262
- } else if (stat.isFile()) {
263
- files.push(normalizePath(relative(root, path)));
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
+ }
264
270
  }
265
271
  }
266
272
  return files;
267
273
  }
268
- function copyIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest, include) {
269
- const matchers = getIncludeMatchers(include);
270
- if (matchers.length === 0)
271
- return 0;
272
- const mappedOutputPaths = new Set(manifest.files.map((file) => normalizePath(file.outputPath)));
273
- const mapRelativePath = normalizePath(relative(renderedRoot, mapPath));
274
- const directoryMap = buildDirectoryMap(manifest);
274
+ function copyIncludedRenderedFiles(renderedRoot, templateRoot, includedOutputPaths, directoryMap) {
275
275
  let filesWritten = 0;
276
- for (const outputPath of walkFiles(renderedRoot)) {
277
- if (outputPath === mapRelativePath)
278
- continue;
279
- if (mappedOutputPaths.has(outputPath))
280
- continue;
281
- if (!matchesAny(outputPath, matchers))
282
- continue;
276
+ for (const outputPath of includedOutputPaths) {
283
277
  const renderedPath = resolveInside(renderedRoot, outputPath);
284
278
  const templatePath = resolveInside(templateRoot, inferTemplatePath(outputPath, directoryMap));
285
279
  mkdirSync(dirname(templatePath), { recursive: true });
@@ -288,11 +282,23 @@ function copyIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest
288
282
  }
289
283
  return filesWritten;
290
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
+ }
291
295
  function reverseDir(renderedDir, templateDir, options = {}) {
292
296
  const renderedRoot = resolvePath(renderedDir);
293
297
  const templateRoot = resolvePath(templateDir);
294
298
  const mapPath = options.mapPath ? resolvePath(renderedRoot, options.mapPath) : resolvePath(renderedRoot, ".tdir-map.json");
295
299
  const manifest = readManifest(mapPath);
300
+ const directoryMap = buildDirectoryMap(manifest);
301
+ const includedOutputPaths = getIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest, options.include);
296
302
  const warnings = [];
297
303
  let filesWritten = 0;
298
304
  for (const file of manifest.files) {
@@ -327,7 +333,7 @@ function reverseDir(renderedDir, templateDir, options = {}) {
327
333
  for (const skipped of manifest.skipped ?? []) {
328
334
  filesWritten += writeSkippedTemplate(templateRoot, skipped);
329
335
  }
330
- filesWritten += copyIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest, options.include);
336
+ filesWritten += copyIncludedRenderedFiles(renderedRoot, templateRoot, includedOutputPaths, directoryMap);
331
337
  return { filesWritten, warnings };
332
338
  }
333
339
 
package/dist/index.js CHANGED
@@ -738,34 +738,28 @@ function inferTemplatePath(outputPath, directoryMap) {
738
738
  const suffix = bestOutputDir === "" ? outputDir : outputDir.slice(bestOutputDir.length).replace(/^\//, "");
739
739
  return joinPath(bestTemplateDir, suffix, basenamePath(normalized));
740
740
  }
741
- function walkFiles(root, current = root) {
741
+ function walkFiles(root, excludedRoots = []) {
742
742
  const files = [];
743
- for (const entry of readdirSync3(current).sort()) {
744
- const path = resolvePath2(current, entry);
745
- const stat = statSync3(path);
746
- if (stat.isDirectory()) {
747
- files.push(...walkFiles(root, path));
748
- } else if (stat.isFile()) {
749
- files.push(normalizePath(relative2(root, path)));
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
+ }
750
756
  }
751
757
  }
752
758
  return files;
753
759
  }
754
- function copyIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest, include) {
755
- const matchers = getIncludeMatchers(include);
756
- if (matchers.length === 0)
757
- return 0;
758
- const mappedOutputPaths = new Set(manifest.files.map((file) => normalizePath(file.outputPath)));
759
- const mapRelativePath = normalizePath(relative2(renderedRoot, mapPath));
760
- const directoryMap = buildDirectoryMap(manifest);
760
+ function copyIncludedRenderedFiles(renderedRoot, templateRoot, includedOutputPaths, directoryMap) {
761
761
  let filesWritten = 0;
762
- for (const outputPath of walkFiles(renderedRoot)) {
763
- if (outputPath === mapRelativePath)
764
- continue;
765
- if (mappedOutputPaths.has(outputPath))
766
- continue;
767
- if (!matchesAny(outputPath, matchers))
768
- continue;
762
+ for (const outputPath of includedOutputPaths) {
769
763
  const renderedPath = resolveInside(renderedRoot, outputPath);
770
764
  const templatePath = resolveInside(templateRoot, inferTemplatePath(outputPath, directoryMap));
771
765
  mkdirSync2(dirname2(templatePath), { recursive: true });
@@ -774,11 +768,23 @@ function copyIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest
774
768
  }
775
769
  return filesWritten;
776
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
+ }
777
781
  function reverseDir(renderedDir, templateDir, options = {}) {
778
782
  const renderedRoot = resolvePath2(renderedDir);
779
783
  const templateRoot = resolvePath2(templateDir);
780
784
  const mapPath = options.mapPath ? resolvePath2(renderedRoot, options.mapPath) : resolvePath2(renderedRoot, ".tdir-map.json");
781
785
  const manifest = readManifest(mapPath);
786
+ const directoryMap = buildDirectoryMap(manifest);
787
+ const includedOutputPaths = getIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest, options.include);
782
788
  const warnings = [];
783
789
  let filesWritten = 0;
784
790
  for (const file of manifest.files) {
@@ -813,7 +819,7 @@ function reverseDir(renderedDir, templateDir, options = {}) {
813
819
  for (const skipped of manifest.skipped ?? []) {
814
820
  filesWritten += writeSkippedTemplate(templateRoot, skipped);
815
821
  }
816
- filesWritten += copyIncludedRenderedFiles(renderedRoot, templateRoot, mapPath, manifest, options.include);
822
+ filesWritten += copyIncludedRenderedFiles(renderedRoot, templateRoot, includedOutputPaths, directoryMap);
817
823
  return { filesWritten, warnings };
818
824
  }
819
825
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gregorlohaus/tdir",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",