Skip to content

Commit d64ca6f

Browse files
authored
[ENG-278] Bulk import discourse nodes on Obsidian (#225)
* curr progress * cleanup * try catch * with folder path and test script * address PR comments * cur progress * address PR comments
1 parent 2294492 commit d64ca6f

8 files changed

Lines changed: 819 additions & 4 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env tsx
2+
3+
import { promises as fs } from "fs";
4+
import * as path from "path";
5+
6+
/**
7+
* Generates a set of markdown files that match the naming pattern
8+
* for each default discourse node type. Useful for stress-testing the
9+
* bulk-import feature without relying on external data sources.
10+
*/
11+
12+
const VAULT_PATH = "/Users/trang.doan/Documents/Trang Doan";
13+
const TEST_FOLDER = "test-bulk-import-generated";
14+
const FILES_PER_TYPE = 300;
15+
16+
/** Minimal representation of the default node types. */
17+
const DEFAULT_NODE_TYPES: { name: string; format: string }[] = [
18+
{ name: "Question", format: "QUE - {content}" },
19+
{ name: "Claim", format: "CLM - {content}" },
20+
{ name: "Evidence", format: "EVD - {content}" },
21+
];
22+
23+
async function main() {
24+
const targetDir = path.join(VAULT_PATH, TEST_FOLDER);
25+
26+
console.log("🧪 Generating test files for bulk import…\n");
27+
28+
// Clean existing folder if present
29+
try {
30+
await fs.rm(targetDir, { recursive: true, force: true });
31+
console.log("🧹 Removed existing test folder (if any)");
32+
} catch (_) {
33+
/* noop */
34+
}
35+
36+
// Ensure target directory exists
37+
await fs.mkdir(targetDir, { recursive: true });
38+
console.log(`📁 Created test folder: ${targetDir}\n`);
39+
40+
for (const nodeType of DEFAULT_NODE_TYPES) {
41+
console.log(`📄 Creating ${FILES_PER_TYPE} ${nodeType.name} files…`);
42+
43+
for (let i = 1; i <= FILES_PER_TYPE; i++) {
44+
const contentPlaceholder = `${nodeType.name} ${String(i).padStart(3, "0")}`;
45+
const title = nodeType.format.replace("{content}", contentPlaceholder);
46+
const filename = `${title}.md`;
47+
const filePath = path.join(targetDir, filename);
48+
49+
const body = `# ${title}\n\nAutomatically generated for bulk-import testing.`;
50+
await fs.writeFile(filePath, body, "utf8");
51+
}
52+
53+
console.log(` ✅ Done (${FILES_PER_TYPE} files)`);
54+
}
55+
56+
console.log("\n🎉 Test file generation complete!");
57+
console.log(`📍 Location: ${targetDir}\n`);
58+
}
59+
60+
if (require.main === module) {
61+
main().catch((err) => {
62+
console.error("💥 Generation failed:", err);
63+
process.exit(1);
64+
});
65+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/env tsx
2+
3+
import { promises as fs } from "fs";
4+
import * as path from "path";
5+
6+
const VAULT_PATH = "/Users/trang.doan/Documents/Trang Doan";
7+
const TEST_FOLDER = "test-bulk-import";
8+
const SOURCE_DIR = "/Users/trang.doan/Downloads/notes-hugo/discourse-graph";
9+
10+
async function setupTestData() {
11+
const testFolderPath = path.join(VAULT_PATH, TEST_FOLDER);
12+
13+
console.log("🧪 Setting up bulk import test data...");
14+
15+
try {
16+
// Remove existing test folder if it exists
17+
try {
18+
await fs.access(testFolderPath);
19+
console.log("📁 Removing existing test folder...");
20+
await fs.rm(testFolderPath, { recursive: true, force: true });
21+
} catch (error) {
22+
// Folder doesn't exist, which is fine
23+
}
24+
25+
// Check if source directory exists
26+
try {
27+
await fs.access(SOURCE_DIR);
28+
console.log("✅ Source directory found");
29+
} catch (error) {
30+
console.error(`❌ Source directory not found: ${SOURCE_DIR}`);
31+
process.exit(1);
32+
}
33+
34+
// Show source directory structure and counts
35+
console.log("📊 Analyzing source directory...");
36+
await showDirectoryStats(SOURCE_DIR);
37+
38+
// Create test folder
39+
console.log("📁 Creating test folder...");
40+
await fs.mkdir(testFolderPath, { recursive: true });
41+
42+
// Copy files from source to test folder
43+
console.log("📄 Copying test files...");
44+
const fileCount = await copyDirectoryRecursive(SOURCE_DIR, testFolderPath);
45+
46+
console.log(`🎉 Successfully created test folder with ${fileCount} files!`);
47+
console.log(`📍 Location: ${testFolderPath}`);
48+
} catch (error) {
49+
console.error("❌ Error setting up test data:", error);
50+
process.exit(1);
51+
}
52+
}
53+
54+
async function copyDirectoryRecursive(
55+
source: string,
56+
target: string,
57+
): Promise<number> {
58+
let fileCount = 0;
59+
60+
const copyRecursive = async (src: string, dest: string): Promise<void> => {
61+
const items = await fs.readdir(src, { withFileTypes: true });
62+
63+
for (const item of items) {
64+
const srcPath = path.join(src, item.name);
65+
const destPath = path.join(dest, item.name);
66+
67+
if (item.isDirectory()) {
68+
console.log(`📁 Creating folder: ${path.relative(target, destPath)}`);
69+
await fs.mkdir(destPath, { recursive: true });
70+
await copyRecursive(srcPath, destPath);
71+
} else if (
72+
item.isFile() &&
73+
(item.name.endsWith(".md") || item.name.endsWith(".txt"))
74+
) {
75+
// Only copy markdown and text files
76+
console.log(`📄 Copying: ${path.relative(target, destPath)}`);
77+
await fs.copyFile(srcPath, destPath);
78+
fileCount++;
79+
}
80+
}
81+
};
82+
83+
await copyRecursive(source, target);
84+
return fileCount;
85+
}
86+
87+
async function showDirectoryStats(
88+
dir: string,
89+
level: number = 0,
90+
): Promise<void> {
91+
const indent = " ".repeat(level);
92+
const items = await fs.readdir(dir, { withFileTypes: true });
93+
94+
let fileCount = 0;
95+
let dirCount = 0;
96+
97+
for (const item of items) {
98+
if (item.isDirectory()) {
99+
dirCount++;
100+
} else if (
101+
item.isFile() &&
102+
(item.name.endsWith(".md") || item.name.endsWith(".txt"))
103+
) {
104+
fileCount++;
105+
}
106+
}
107+
108+
console.log(
109+
`${indent}📁 ${path.basename(dir)}: ${fileCount} files, ${dirCount} subdirectories`,
110+
);
111+
112+
// Recursively show subdirectories (but limit depth to avoid clutter)
113+
if (level < 2) {
114+
for (const item of items) {
115+
if (item.isDirectory()) {
116+
await showDirectoryStats(path.join(dir, item.name), level + 1);
117+
}
118+
}
119+
}
120+
}
121+
122+
// Run the script
123+
if (require.main === module) {
124+
setupTestData().catch((error) => {
125+
console.error("💥 Script failed:", error);
126+
process.exit(1);
127+
});
128+
}

0 commit comments

Comments
 (0)