mirror of
https://github.com/devonthesofa/obsidian-note-status.git
synced 2026-07-22 12:30:24 +00:00
297 lines
7.5 KiB
TypeScript
297 lines
7.5 KiB
TypeScript
#!/usr/bin/env tsx
|
|
/**
|
|
* Obsidian Test Vault Generator
|
|
*
|
|
* This script generates a large number of markdown files with status tags
|
|
* to test the performance of the Note Status plugin with large vaults.
|
|
*
|
|
* Usage:
|
|
* npx tsx generate-test-vault.ts --count 40000 --output ./test-vault
|
|
*/
|
|
|
|
import * as fs from "fs";
|
|
import * as path from "path";
|
|
import { program } from "commander";
|
|
|
|
// Define command line options
|
|
program
|
|
.option("-c, --count <number>", "Number of notes to generate", "40000")
|
|
.option("-o, --output <path>", "Output directory path", "./test-vault")
|
|
.option(
|
|
"-t, --tag-prefix <string>",
|
|
"Status tag prefix",
|
|
"obsidian-note-status",
|
|
)
|
|
.option("-d, --depth <number>", "Maximum folder depth", "5")
|
|
.option("-m, --max-per-folder <number>", "Maximum files per folder", "200")
|
|
.option("-n, --no-status", "Generate notes without status tags")
|
|
.parse(process.argv);
|
|
|
|
const options = program.opts();
|
|
|
|
// Validate options
|
|
const noteCount = parseInt(options.count, 10);
|
|
const outputDir = options.output;
|
|
const tagPrefix = options.tagPrefix;
|
|
const maxDepth = parseInt(options.depth, 10);
|
|
const maxPerFolder = parseInt(options.maxPerFolder, 10);
|
|
const includeStatus = options.status !== false; // true by default, false if --no-status is used
|
|
|
|
if (isNaN(noteCount) || noteCount <= 0) {
|
|
console.error("Error: Note count must be a positive number");
|
|
process.exit(1);
|
|
}
|
|
|
|
// Define possible statuses (matching your plugin's defaults)
|
|
const statuses = [
|
|
"active",
|
|
"onHold",
|
|
"completed",
|
|
"dropped",
|
|
"unknown",
|
|
// Add some from the colorful template
|
|
"idea",
|
|
"draft",
|
|
"inProgress",
|
|
"editing",
|
|
"pending",
|
|
];
|
|
|
|
// Define topics for more realistic note titles
|
|
const topics = [
|
|
"Project",
|
|
"Meeting",
|
|
"Research",
|
|
"Idea",
|
|
"Book",
|
|
"Journal",
|
|
"Task",
|
|
"Recipe",
|
|
"Person",
|
|
"Place",
|
|
"Event",
|
|
"Course",
|
|
"Paper",
|
|
"Review",
|
|
"Analysis",
|
|
"Summary",
|
|
"Plan",
|
|
"Design",
|
|
"Budget",
|
|
"Report",
|
|
"Feature",
|
|
"Bug",
|
|
"Release",
|
|
"Backlog",
|
|
"Sprint",
|
|
"Goal",
|
|
"OKR",
|
|
"KPI",
|
|
"Metric",
|
|
"Reflection",
|
|
];
|
|
|
|
// Generate a random status
|
|
function getRandomStatus(): string {
|
|
const multipleStatuses = Math.random() > 0.8; // 20% chance of multiple statuses
|
|
|
|
if (multipleStatuses) {
|
|
const count = Math.floor(Math.random() * 2) + 2; // 2-3 statuses
|
|
const selectedStatuses = new Set<string>();
|
|
|
|
while (selectedStatuses.size < count) {
|
|
selectedStatuses.add(
|
|
statuses[Math.floor(Math.random() * statuses.length)],
|
|
);
|
|
}
|
|
|
|
return JSON.stringify(Array.from(selectedStatuses));
|
|
} else {
|
|
return JSON.stringify([
|
|
statuses[Math.floor(Math.random() * statuses.length)],
|
|
]);
|
|
}
|
|
}
|
|
|
|
// Generate a random title
|
|
function generateTitle(): string {
|
|
const topic = topics[Math.floor(Math.random() * topics.length)];
|
|
const qualifier =
|
|
Math.random() > 0.5
|
|
? [
|
|
"New",
|
|
"Important",
|
|
"Urgent",
|
|
"Weekly",
|
|
"Monthly",
|
|
"Daily",
|
|
"Annual",
|
|
][Math.floor(Math.random() * 7)]
|
|
: "";
|
|
const number =
|
|
Math.random() > 0.3 ? Math.floor(Math.random() * 1000).toString() : "";
|
|
|
|
return [qualifier, topic, number].filter(Boolean).join(" ").trim();
|
|
}
|
|
|
|
// Generate note content with random length
|
|
function generateContent(): string {
|
|
const paragraphCount = Math.floor(Math.random() * 5) + 1;
|
|
let content = "";
|
|
|
|
for (let i = 0; i < paragraphCount; i++) {
|
|
const sentenceCount = Math.floor(Math.random() * 5) + 1;
|
|
let paragraph = "";
|
|
|
|
for (let j = 0; j < sentenceCount; j++) {
|
|
const wordCount = Math.floor(Math.random() * 15) + 5;
|
|
const sentence = Array(wordCount).fill("lorem").join(" ") + ". ";
|
|
paragraph += sentence;
|
|
}
|
|
|
|
content += paragraph + "\n\n";
|
|
}
|
|
|
|
return content;
|
|
}
|
|
|
|
// Create a note with optional frontmatter containing status
|
|
function createNote(title: string, folderPath: string): void {
|
|
const safeName = title.replace(/[^a-zA-Z0-9 ]/g, "").replace(/\s+/g, " ");
|
|
const fileName = `${safeName}.md`;
|
|
const filePath = path.join(folderPath, fileName);
|
|
|
|
let fileContent = "";
|
|
|
|
if (includeStatus) {
|
|
// Create frontmatter with random status
|
|
const status = getRandomStatus();
|
|
fileContent = `---\n${tagPrefix}: ${status}\n---\n\n`;
|
|
}
|
|
|
|
// Create content
|
|
fileContent += `# ${title}\n\n${generateContent()}`;
|
|
|
|
// Write file
|
|
fs.writeFileSync(filePath, fileContent);
|
|
}
|
|
|
|
// Generate a folder structure and notes
|
|
function generateNotes(count: number, baseDir: string): void {
|
|
// Create base directory if it doesn't exist
|
|
if (!fs.existsSync(baseDir)) {
|
|
fs.mkdirSync(baseDir, { recursive: true });
|
|
}
|
|
|
|
// Track created files
|
|
let created = 0;
|
|
let foldersCreated = 0;
|
|
|
|
// Create a function to generate notes in a folder with recursion
|
|
function generateNotesInFolder(folderPath: string, depth: number): void {
|
|
if (created >= count) return;
|
|
|
|
// Determine how many files to create in this folder
|
|
const filesInThisFolder = Math.min(
|
|
Math.floor(Math.random() * maxPerFolder) + 1,
|
|
count - created,
|
|
);
|
|
|
|
// Create files in this folder
|
|
for (let i = 0; i < filesInThisFolder; i++) {
|
|
if (created >= count) break;
|
|
|
|
const title = generateTitle();
|
|
createNote(title, folderPath);
|
|
created++;
|
|
|
|
// Display progress
|
|
if (created % 1000 === 0 || created === count) {
|
|
console.log(`Created ${created}/${count} notes...`);
|
|
}
|
|
}
|
|
|
|
// Possibly create subfolders if not at max depth
|
|
if (depth < maxDepth && created < count) {
|
|
// Decide how many subfolders to create
|
|
const subfoldersCount = Math.floor(Math.random() * 5) + 1;
|
|
|
|
for (let i = 0; i < subfoldersCount; i++) {
|
|
if (created >= count) break;
|
|
|
|
const folderName = `Folder ${++foldersCreated}`;
|
|
const subfolderPath = path.join(folderPath, folderName);
|
|
|
|
// Create subfolder
|
|
if (!fs.existsSync(subfolderPath)) {
|
|
fs.mkdirSync(subfolderPath);
|
|
}
|
|
|
|
// Recursively generate notes in subfolder
|
|
generateNotesInFolder(subfolderPath, depth + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Start generation
|
|
generateNotesInFolder(baseDir, 0);
|
|
|
|
console.log(
|
|
`\nSuccessfully created ${created} notes in ${foldersCreated} folders.`,
|
|
);
|
|
console.log(`Output directory: ${path.resolve(baseDir)}`);
|
|
}
|
|
|
|
// Create .obsidian folder with minimal config to ensure it's recognized as a vault
|
|
function createObsidianConfig(baseDir: string): void {
|
|
const obsidianDir = path.join(baseDir, ".obsidian");
|
|
if (!fs.existsSync(obsidianDir)) {
|
|
fs.mkdirSync(obsidianDir, { recursive: true });
|
|
}
|
|
|
|
// Create a minimal config.json
|
|
const configPath = path.join(obsidianDir, "config.json");
|
|
const config = {
|
|
baseFontSize: 16,
|
|
pluginEnabledStatus: {
|
|
"file-explorer": true,
|
|
"global-search": true,
|
|
switcher: true,
|
|
graph: true,
|
|
backlink: true,
|
|
"page-preview": true,
|
|
templates: true,
|
|
},
|
|
};
|
|
|
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
|
|
// Create a minimal appearance.json
|
|
const appearancePath = path.join(obsidianDir, "appearance.json");
|
|
const appearance = {
|
|
baseFontSize: 16,
|
|
theme: "obsidian",
|
|
};
|
|
|
|
fs.writeFileSync(appearancePath, JSON.stringify(appearance, null, 2));
|
|
}
|
|
|
|
// Main execution
|
|
console.log(
|
|
`Generating ${noteCount} notes in ${outputDir}${includeStatus ? ` with tag prefix '${tagPrefix}'` : " without status tags"}`,
|
|
);
|
|
console.time("Generation completed in");
|
|
|
|
// Create test vault
|
|
generateNotes(noteCount, outputDir);
|
|
|
|
// Create Obsidian configuration
|
|
createObsidianConfig(outputDir);
|
|
|
|
console.timeEnd("Generation completed in");
|
|
console.log("\nInstructions:");
|
|
console.log("1. Open Obsidian");
|
|
console.log('2. Select "Open folder as vault"');
|
|
console.log(`3. Navigate to: ${path.resolve(outputDir)}`);
|
|
console.log("4. Install and enable your Note Status plugin");
|
|
console.log("5. Test the plugin performance with this large vault");
|