summaryrefslogtreecommitdiff
path: root/build.js
blob: af6ed4db0e8f6c9b48b520443217594619bf484c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/env node
/**
 * Site Generator
 *
 * Reads markdown summaries from summaries/{id}.md and embeds them into
 * data/books.json, then creates a dist directory with all static assets.
 *
 * Usage: node build.js
 *
 * Run this after editing any summary markdown files.
 */

const fs = require('fs');
const path = require('path');

const ROOT_DIR = __dirname;
const SUMMARIES_DIR = path.join(ROOT_DIR, 'summaries');
const BOOKS_JSON = path.join(ROOT_DIR, 'data', 'books.json');
const DIST_DIR = path.join(ROOT_DIR, 'dist');

function readSummary(id) {
  const filePath = path.join(SUMMARIES_DIR, `${id}.md`);

  if (!fs.existsSync(filePath)) {
    return null;
  }

  const content = fs.readFileSync(filePath, 'utf8').trim();
  const lines = content.split('\n');

  // Skip the title line (# Title) and return the rest
  const summaryLines = lines.slice(1).join('\n').trim();
  return summaryLines || null;
}

/**
 * Recursively copies a directory from src to dest.
 */
function copyDir(src, dest) {
  fs.mkdirSync(dest, { recursive: true });
  const entries = fs.readdirSync(src, { withFileTypes: true });

  for (const entry of entries) {
    const srcPath = path.join(src, entry.name);
    const destPath = path.join(dest, entry.name);

    if (entry.isDirectory()) {
      copyDir(srcPath, destPath);
    } else {
      fs.copyFileSync(srcPath, destPath);
    }
  }
}

/**
 * Embeds summaries from markdown files into books.json.
 * Returns the updated books data.
 */
function embedSummaries() {
  console.log('Embedding summaries...\n');

  const booksData = JSON.parse(fs.readFileSync(BOOKS_JSON, 'utf8'));

  let updated = 0;
  let missing = [];

  for (const book of booksData.books) {
    const summary = readSummary(book.id);

    if (summary) {
      book.summary = summary;
      updated++;
      console.log(`✓ ${book.title}`);
    } else {
      delete book.summary;
      missing.push(book.title);
      console.log(`✗ ${book.title} (no summary file)`);
    }
  }

  fs.writeFileSync(BOOKS_JSON, JSON.stringify(booksData, null, 2));

  console.log(`\nSummaries embedded: ${updated}`);
  console.log(`Missing summaries: ${missing.length}`);

  if (missing.length > 0) {
    console.log('\nCreate these files to add summaries:');
    missing.forEach(title => {
      const book = booksData.books.find(b => b.title === title);
      console.log(`  summaries/${book.id}.md`);
    });
  }

  return booksData;
}

/**
 * Creates the dist directory with all static assets for distribution.
 */
function createDist() {
  console.log('\n--- Creating dist directory ---\n');

  // Remove existing dist directory
  if (fs.existsSync(DIST_DIR)) {
    fs.rmSync(DIST_DIR, { recursive: true });
  }
  fs.mkdirSync(DIST_DIR);

  // Copy static files
  fs.copyFileSync(path.join(ROOT_DIR, 'index.html'), path.join(DIST_DIR, 'index.html'));
  console.log('✓ index.html');

  // Copy directories
  copyDir(path.join(ROOT_DIR, 'css'), path.join(DIST_DIR, 'css'));
  console.log('✓ css/');

  copyDir(path.join(ROOT_DIR, 'js'), path.join(DIST_DIR, 'js'));
  console.log('✓ js/');

  copyDir(path.join(ROOT_DIR, 'data'), path.join(DIST_DIR, 'data'));
  console.log('✓ data/');

  copyDir(path.join(ROOT_DIR, 'images'), path.join(DIST_DIR, 'images'));
  console.log('✓ images/');

  console.log('\nDist directory created at: dist/');
}

function build() {
  console.log('=== Building Site ===\n');

  embedSummaries();
  createDist();

  console.log('\n=== Build Complete ===');
  console.log('Site is ready. Open dist/index.html in a browser.');
}

build();